提交 8ac5496d 编写于 作者: Z zgu

7071311: Decoder enhancement

Summary: Made decoder thread-safe
Reviewed-by: coleenp, kamg
上级 887fcf69
/*
* Copyright (c) 2011, 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"
#ifdef __APPLE__
#include "decoder_machO.hpp"
#endif
/* /*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -22,45 +22,21 @@ ...@@ -22,45 +22,21 @@
* *
*/ */
#include "prims/jvm.h" #ifndef OS_BSD_VM_DECODER_MACHO_HPP
#include "utilities/decoder.hpp" #define OS_BSD_VM_DECODER_MACHO_HPP
#include <cxxabi.h>
#ifdef __APPLE__ #ifdef __APPLE__
void Decoder::initialize() { #include "utilities/decoder.hpp"
_initialized = true;
}
void Decoder::uninitialize() {
_initialized = false;
}
bool Decoder::can_decode_C_frame_in_vm() {
return false;
}
Decoder::decoder_status Decoder::decode(address addr, const char* filepath, char *buf, int buflen, int *offset) {
return symbol_not_found;
}
// Just a placehold for now
class MachODecoder: public NullDecoder {
public:
MachODecoder() { }
~MachODecoder() { }
};
#endif #endif
bool Decoder::demangle(const char* symbol, char *buf, int buflen) { #endif // OS_BSD_VM_DECODER_MACHO_HPP
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;
}
...@@ -23,11 +23,11 @@ ...@@ -23,11 +23,11 @@
*/ */
#include "prims/jvm.h" #include "prims/jvm.h"
#include "utilities/decoder.hpp" #include "utilities/decoder_elf.hpp"
#include <cxxabi.h> #include <cxxabi.h>
bool Decoder::demangle(const char* symbol, char *buf, int buflen) { bool ElfDecoder::demangle(const char* symbol, char *buf, int buflen) {
int status; int status;
char* result; char* result;
size_t size = (size_t)buflen; size_t size = (size_t)buflen;
...@@ -43,3 +43,4 @@ bool Decoder::demangle(const char* symbol, char *buf, int buflen) { ...@@ -43,3 +43,4 @@ bool Decoder::demangle(const char* symbol, char *buf, int buflen) {
} }
return false; return false;
} }
...@@ -1732,7 +1732,7 @@ bool os::dll_address_to_function_name(address addr, char *buf, ...@@ -1732,7 +1732,7 @@ bool os::dll_address_to_function_name(address addr, char *buf,
return true; return true;
} else if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) { } else if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) {
if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase), if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
dlinfo.dli_fname, buf, buflen, offset) == Decoder::no_error) { buf, buflen, offset, dlinfo.dli_fname)) {
return true; return true;
} }
} }
......
...@@ -22,10 +22,11 @@ ...@@ -22,10 +22,11 @@
* *
*/ */
#include "utilities/decoder.hpp" #include "utilities/decoder_elf.hpp"
#include <demangle.h> #include <demangle.h>
bool Decoder::demangle(const char* symbol, char *buf, int buflen) { bool ElfDecoder::demangle(const char* symbol, char *buf, int buflen) {
return !cplus_demangle(symbol, buf, (size_t)buflen); return !cplus_demangle(symbol, buf, (size_t)buflen);
} }
...@@ -1997,7 +1997,7 @@ bool os::dll_address_to_function_name(address addr, char *buf, ...@@ -1997,7 +1997,7 @@ bool os::dll_address_to_function_name(address addr, char *buf,
} }
if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) { if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) {
if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase), if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
dlinfo.dli_fname, buf, buflen, offset) == Decoder::no_error) { buf, buflen, offset, dlinfo.dli_fname)) {
return true; return true;
} }
} }
...@@ -2015,7 +2015,7 @@ bool os::dll_address_to_function_name(address addr, char *buf, ...@@ -2015,7 +2015,7 @@ bool os::dll_address_to_function_name(address addr, char *buf,
return true; return true;
} else if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) { } else if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) {
if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase), if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
dlinfo.dli_fname, buf, buflen, offset) == Decoder::no_error) { buf, buflen, offset, dlinfo.dli_fname)) {
return true; return true;
} }
} }
......
/* /*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -24,19 +24,21 @@ ...@@ -24,19 +24,21 @@
#include "precompiled.hpp" #include "precompiled.hpp"
#include "prims/jvm.h" #include "prims/jvm.h"
#include "runtime/os.hpp" #include "decoder_windows.hpp"
#include "utilities/decoder.hpp"
HMODULE Decoder::_dbghelp_handle = NULL; WindowsDecoder::WindowsDecoder() {
bool Decoder::_can_decode_in_vm = false; _dbghelp_handle = NULL;
pfn_SymGetSymFromAddr64 Decoder::_pfnSymGetSymFromAddr64 = NULL; _can_decode_in_vm = false;
pfn_UndecorateSymbolName Decoder::_pfnUndecorateSymbolName = NULL; _pfnSymGetSymFromAddr64 = NULL;
_pfnUndecorateSymbolName = NULL;
void Decoder::initialize() { _decoder_status = no_error;
if (!_initialized) { initialize();
_initialized = true; }
HINSTANCE handle = os::win32::load_Windows_dll("dbghelp.dll", NULL, 0); void WindowsDecoder::initialize() {
if (!has_error() && _dbghelp_handle == NULL) {
HMODULE handle = ::LoadLibrary("dbghelp.dll");
if (!handle) { if (!handle) {
_decoder_status = helper_not_found; _decoder_status = helper_not_found;
return; return;
...@@ -70,32 +72,29 @@ void Decoder::initialize() { ...@@ -70,32 +72,29 @@ void Decoder::initialize() {
// find out if jvm.dll contains private symbols, by decoding // find out if jvm.dll contains private symbols, by decoding
// current function and comparing the result // current function and comparing the result
address addr = (address)Decoder::initialize; address addr = (address)Decoder::decode;
char buf[MAX_PATH]; char buf[MAX_PATH];
if (decode(addr, buf, sizeof(buf), NULL) == no_error) { if (decode(addr, buf, sizeof(buf), NULL)) {
_can_decode_in_vm = !strcmp(buf, "Decoder::initialize"); _can_decode_in_vm = !strcmp(buf, "Decoder::decode");
} }
} }
} }
void Decoder::uninitialize() { void WindowsDecoder::uninitialize() {
assert(_initialized, "Decoder not yet initialized");
_pfnSymGetSymFromAddr64 = NULL; _pfnSymGetSymFromAddr64 = NULL;
_pfnUndecorateSymbolName = NULL; _pfnUndecorateSymbolName = NULL;
if (_dbghelp_handle != NULL) { if (_dbghelp_handle != NULL) {
::FreeLibrary(_dbghelp_handle); ::FreeLibrary(_dbghelp_handle);
} }
_initialized = false; _dbghelp_handle = NULL;
} }
bool Decoder::can_decode_C_frame_in_vm() { bool WindowsDecoder::can_decode_C_frame_in_vm() const {
initialize(); return (!has_error() && _can_decode_in_vm);
return _can_decode_in_vm;
} }
Decoder::decoder_status Decoder::decode(address addr, char *buf, int buflen, int *offset) { bool WindowsDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* modulepath) {
assert(_initialized, "Decoder not yet initialized");
if (_pfnSymGetSymFromAddr64 != NULL) { if (_pfnSymGetSymFromAddr64 != NULL) {
PIMAGEHLP_SYMBOL64 pSymbol; PIMAGEHLP_SYMBOL64 pSymbol;
char symbolInfo[MAX_PATH + sizeof(IMAGEHLP_SYMBOL64)]; char symbolInfo[MAX_PATH + sizeof(IMAGEHLP_SYMBOL64)];
...@@ -105,19 +104,20 @@ Decoder::decoder_status Decoder::decode(address addr, char *buf, int buflen, int ...@@ -105,19 +104,20 @@ Decoder::decoder_status Decoder::decode(address addr, char *buf, int buflen, int
DWORD64 displacement; DWORD64 displacement;
if (_pfnSymGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) { if (_pfnSymGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) {
if (buf != NULL) { if (buf != NULL) {
if (!demangle(pSymbol->Name, buf, buflen)) { if (demangle(pSymbol->Name, buf, buflen)) {
jio_snprintf(buf, buflen, "%s", pSymbol->Name); jio_snprintf(buf, buflen, "%s", pSymbol->Name);
} }
} }
if (offset != NULL) *offset = (int)displacement; if(offset != NULL) *offset = (int)displacement;
return no_error; return true;
} }
} }
return helper_not_found; if (buf != NULL && buflen > 0) buf[0] = '\0';
if (offset != NULL) *offset = -1;
return false;
} }
bool Decoder::demangle(const char* symbol, char *buf, int buflen) { bool WindowsDecoder::demangle(const char* symbol, char *buf, int buflen) {
assert(_initialized, "Decoder not yet initialized");
return _pfnUndecorateSymbolName != NULL && return _pfnUndecorateSymbolName != NULL &&
_pfnUndecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE); _pfnUndecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE);
} }
......
/*
* Copyright (c) 2011, 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 OS_WINDOWS_VM_DECODER_WINDOWS_HPP
#define OS_WINDOWS_VM_DECIDER_WINDOWS_HPP
#include <windows.h>
#include <imagehlp.h>
#include "utilities/decoder.hpp"
// 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);
class WindowsDecoder: public NullDecoder {
public:
WindowsDecoder();
~WindowsDecoder() { uninitialize(); };
bool can_decode_C_frame_in_vm() const;
bool demangle(const char* symbol, char *buf, int buflen);
bool decode(address addr, char *buf, int buflen, int* offset, const char* modulepath = NULL);
private:
void initialize();
void uninitialize();
private:
HMODULE _dbghelp_handle;
bool _can_decode_in_vm;
pfn_SymGetSymFromAddr64 _pfnSymGetSymFromAddr64;
pfn_UndecorateSymbolName _pfnUndecorateSymbolName;
};
#endif // OS_WINDOWS_VM_DECODER_WINDOWS_HPP
...@@ -1391,7 +1391,7 @@ bool os::dll_address_to_library_name(address addr, char* buf, ...@@ -1391,7 +1391,7 @@ bool os::dll_address_to_library_name(address addr, char* buf,
bool os::dll_address_to_function_name(address addr, char *buf, bool os::dll_address_to_function_name(address addr, char *buf,
int buflen, int *offset) { int buflen, int *offset) {
if (Decoder::decode(addr, buf, buflen, offset) == Decoder::no_error) { if (Decoder::decode(addr, buf, buflen, offset)) {
return true; return true;
} }
if (offset != NULL) *offset = -1; if (offset != NULL) *offset = -1;
......
...@@ -24,80 +24,85 @@ ...@@ -24,80 +24,85 @@
#include "precompiled.hpp" #include "precompiled.hpp"
#include "prims/jvm.h" #include "prims/jvm.h"
#include "runtime/mutexLocker.hpp"
#include "utilities/decoder.hpp" #include "utilities/decoder.hpp"
Decoder::decoder_status Decoder::_decoder_status = Decoder::no_error; #if defined(_WINDOWS)
bool Decoder::_initialized = false; #include "decoder_windows.hpp"
#elif defined(__APPLE__)
#if !defined(_WINDOWS) && !defined(__APPLE__) #include "decoder_machO.hpp"
#else
#include "decoder_elf.hpp"
#endif
// Implementation of common functionalities among Solaris and Linux NullDecoder* Decoder::_decoder = NULL;
#include "utilities/elfFile.hpp" NullDecoder Decoder::_do_nothing_decoder;
Mutex* Decoder::_decoder_lock = new Mutex(Mutex::safepoint,
"DecoderLock");
ElfFile* Decoder::_opened_elf_files = NULL; // _decoder_lock should already acquired before enter this method
NullDecoder* Decoder::get_decoder() {
assert(_decoder_lock != NULL && _decoder_lock->owned_by_self(),
"Require DecoderLock to enter");
bool Decoder::can_decode_C_frame_in_vm() { if (_decoder != NULL) {
return true; return _decoder;
} }
void Decoder::initialize() { // Decoder is a secondary service. Although, it is good to have,
_initialized = true; // but we can live without it.
} #if defined(_WINDOWS)
_decoder = new (std::nothrow) WindowsDecoder();
#elif defined (__APPLE__)
_decoder = new (std::nothrow)MachODecoder();
#else
_decoder = new (std::nothrow)ElfDecoder();
#endif
void Decoder::uninitialize() { if (_decoder == NULL || _decoder->has_error()) {
if (_opened_elf_files != NULL) { if (_decoder != NULL) {
delete _opened_elf_files; delete _decoder;
_opened_elf_files = NULL; }
_decoder = &_do_nothing_decoder;
} }
_initialized = false; return _decoder;
} }
Decoder::decoder_status Decoder::decode(address addr, const char* filepath, char *buf, int buflen, int *offset) { bool Decoder::decode(address addr, char* buf, int buflen, int* offset, const char* modulepath) {
if (_decoder_status != no_error) { assert(_decoder_lock != NULL, "Just check");
return _decoder_status; MutexLockerEx locker(_decoder_lock, true);
} NullDecoder* decoder = get_decoder();
assert(decoder != NULL, "null decoder");
ElfFile* file = get_elf_file(filepath); return decoder->decode(addr, buf, buflen, offset, modulepath);
if (_decoder_status != no_error) { }
return _decoder_status;
}
const char* symbol = file->decode(addr, offset); bool Decoder::demangle(const char* symbol, char* buf, int buflen) {
if (file->get_status() == out_of_memory) { assert(_decoder_lock != NULL, "Just check");
_decoder_status = out_of_memory; MutexLockerEx locker(_decoder_lock, true);
return _decoder_status; NullDecoder* decoder = get_decoder();
} else if (symbol != NULL) { assert(decoder != NULL, "null decoder");
if (!demangle(symbol, buf, buflen)) { return decoder->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) { bool Decoder::can_decode_C_frame_in_vm() {
if (_decoder_status != no_error) { assert(_decoder_lock != NULL, "Just check");
return NULL; MutexLockerEx locker(_decoder_lock, true);
} NullDecoder* decoder = get_decoder();
ElfFile* file = _opened_elf_files; assert(decoder != NULL, "null decoder");
while (file != NULL) { return decoder->can_decode_C_frame_in_vm();
if (file->same_elf_file(filepath)) { }
return file;
}
file = file->m_next;
}
file = new ElfFile(filepath); // shutdown real decoder and replace it with
if (file == NULL) { // _do_nothing_decoder
_decoder_status = out_of_memory; void Decoder::shutdown() {
} assert(_decoder_lock != NULL, "Just check");
if (_opened_elf_files != NULL) { MutexLockerEx locker(_decoder_lock, true);
file->m_next = _opened_elf_files;
if (_decoder != NULL && _decoder != &_do_nothing_decoder) {
delete _decoder;
} }
_opened_elf_files = file; _decoder = &_do_nothing_decoder;
return file;
} }
#endif
/* /*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -23,83 +23,78 @@ ...@@ -23,83 +23,78 @@
*/ */
#ifndef __DECODER_HPP #ifndef SHARE_VM_UTILITIES_DECODER_HPP
#define __DECODER_HPP #define SHARE_VM_UTILITIES_DECODER_HPP
#include "memory/allocation.hpp" #include "memory/allocation.hpp"
#include "runtime/mutex.hpp"
#ifdef _WINDOWS class NullDecoder: public CHeapObj {
#include <windows.h> public:
#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);
#elif defined(__APPLE__)
#else
class ElfFile;
#endif // _WINDOWS
class Decoder: public StackObj {
public:
// status code for decoding native C frame // status code for decoding native C frame
enum decoder_status { enum decoder_status {
no_error, // successfully decoded frames not_available = -10, // real decoder is not available
no_error = 0, // successfully decoded frames
out_of_memory, // out of memory out_of_memory, // out of memory
file_invalid, // invalid elf file file_invalid, // invalid elf file
file_not_found, // could not found symbol file (on windows), such as jvm.pdb or jvm.map 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_not_found, // could not load dbghelp.dll (Windows only)
helper_func_error, // decoding functions not found (Windows only) helper_func_error, // decoding functions not found (Windows only)
helper_init_error, // SymInitialize failed (Windows only) helper_init_error // SymInitialize failed (Windows only)
symbol_not_found // could not find the symbol
}; };
public: NullDecoder() {
Decoder() { initialize(); }; _decoder_status = not_available;
~Decoder() { uninitialize(); }; }
static bool can_decode_C_frame_in_vm(); ~NullDecoder() {};
virtual bool decode(address pc, char* buf, int buflen, int* offset,
const char* modulepath = NULL) {
return false;
}
static void initialize(); virtual bool demangle(const char* symbol, char* buf, int buflen) {
static void uninitialize(); return false;
}
#ifdef _WINDOWS virtual bool can_decode_C_frame_in_vm() const {
static decoder_status decode(address addr, char *buf, int buflen, int *offset); return false;
#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); virtual decoder_status status() const {
return _decoder_status;
}
static decoder_status get_status() { return _decoder_status; }; virtual bool has_error() const {
return is_error(_decoder_status);
}
#if !defined(_WINDOWS) && !defined(__APPLE__) static bool is_error(decoder_status status) {
private: return (status > 0);
static ElfFile* get_elf_file(const char* filepath); }
#endif // _WINDOWS
protected:
decoder_status _decoder_status;
};
class Decoder: AllStatic {
public:
static bool decode(address pc, char* buf, int buflen, int* offset, const char* modulepath = NULL);
static bool demangle(const char* symbol, char* buf, int buflen);
static bool can_decode_C_frame_in_vm();
static void shutdown();
protected:
static NullDecoder* get_decoder();
private: private:
static decoder_status _decoder_status; static NullDecoder* _decoder;
static bool _initialized; static NullDecoder _do_nothing_decoder;
#ifdef _WINDOWS protected:
static HMODULE _dbghelp_handle; static Mutex* _decoder_lock;
static bool _can_decode_in_vm;
static pfn_SymGetSymFromAddr64 _pfnSymGetSymFromAddr64;
static pfn_UndecorateSymbolName _pfnUndecorateSymbolName;
#elif __APPLE__
#else
static ElfFile* _opened_elf_files;
#endif // _WINDOWS
}; };
#endif // __DECODER_HPP #endif // SHARE_VM_UTILITIES_DECODER_HPP
/*
* Copyright (c) 2011, 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"
#if !defined(_WINDOWS) && !defined(__APPLE__)
#include "decoder_elf.hpp"
ElfDecoder::~ElfDecoder() {
if (_opened_elf_files != NULL) {
delete _opened_elf_files;
_opened_elf_files = NULL;
}
}
bool ElfDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* filepath) {
assert(filepath, "null file path");
assert(buf != NULL && buflen > 0, "Invalid buffer");
if (has_error()) return false;
ElfFile* file = get_elf_file(filepath);
if (file == NULL) {
return false;
}
if (!file->decode(addr, buf, buflen, offset)) {
return false;
}
if (buf[0] != '\0') {
demangle(buf, buf, buflen);
}
return true;
}
ElfFile* ElfDecoder::get_elf_file(const char* filepath) {
ElfFile* file;
file = _opened_elf_files;
while (file != NULL) {
if (file->same_elf_file(filepath)) {
return file;
}
file = file->next();
}
file = new (std::nothrow)ElfFile(filepath);
if (file != NULL) {
if (_opened_elf_files != NULL) {
file->set_next(_opened_elf_files);
}
_opened_elf_files = file;
}
return file;
}
#endif
/*
* Copyright (c) 2011, 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 SHARE_VM_UTILITIES_DECODER_ELF_HPP
#define SHARE_VM_UTILITIES_DECODER_ELF_HPP
#if !defined(_WINDOWS) && !defined(__APPLE__)
#include "utilities/decoder.hpp"
#include "utilities/elfFile.hpp"
class ElfDecoder: public NullDecoder {
public:
ElfDecoder() {
_opened_elf_files = NULL;
_decoder_status = no_error;
}
~ElfDecoder();
bool can_decode_C_frame_in_vm() const { return true; }
bool demangle(const char* symbol, char *buf, int buflen);
bool decode(address addr, char *buf, int buflen, int* offset, const char* filepath = NULL);
private:
ElfFile* get_elf_file(const char* filepath);
private:
ElfFile* _opened_elf_files;
};
#endif
#endif // SHARE_VM_UTILITIES_DECODER_ELF_HPP
...@@ -44,7 +44,7 @@ ElfFile::ElfFile(const char* filepath) { ...@@ -44,7 +44,7 @@ ElfFile::ElfFile(const char* filepath) {
m_string_tables = NULL; m_string_tables = NULL;
m_symbol_tables = NULL; m_symbol_tables = NULL;
m_next = NULL; m_next = NULL;
m_status = Decoder::no_error; m_status = NullDecoder::no_error;
int len = strlen(filepath) + 1; int len = strlen(filepath) + 1;
m_filepath = (const char*)os::malloc(len * sizeof(char)); m_filepath = (const char*)os::malloc(len * sizeof(char));
...@@ -54,10 +54,10 @@ ElfFile::ElfFile(const char* filepath) { ...@@ -54,10 +54,10 @@ ElfFile::ElfFile(const char* filepath) {
if (m_file != NULL) { if (m_file != NULL) {
load_tables(); load_tables();
} else { } else {
m_status = Decoder::file_not_found; m_status = NullDecoder::file_not_found;
} }
} else { } else {
m_status = Decoder::out_of_memory; m_status = NullDecoder::out_of_memory;
} }
} }
...@@ -96,41 +96,41 @@ bool ElfFile::is_elf_file(Elf_Ehdr& hdr) { ...@@ -96,41 +96,41 @@ bool ElfFile::is_elf_file(Elf_Ehdr& hdr) {
bool ElfFile::load_tables() { bool ElfFile::load_tables() {
assert(m_file, "file not open"); assert(m_file, "file not open");
assert(m_status == Decoder::no_error, "already in error"); assert(!NullDecoder::is_error(m_status), "already in error");
// read elf file header // read elf file header
if (fread(&m_elfHdr, sizeof(m_elfHdr), 1, m_file) != 1) { if (fread(&m_elfHdr, sizeof(m_elfHdr), 1, m_file) != 1) {
m_status = Decoder::file_invalid; m_status = NullDecoder::file_invalid;
return false; return false;
} }
if (!is_elf_file(m_elfHdr)) { if (!is_elf_file(m_elfHdr)) {
m_status = Decoder::file_invalid; m_status = NullDecoder::file_invalid;
return false; return false;
} }
// walk elf file's section headers, and load string tables // walk elf file's section headers, and load string tables
Elf_Shdr shdr; Elf_Shdr shdr;
if (!fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) { if (!fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) {
if (m_status != Decoder::no_error) return false; if (NullDecoder::is_error(m_status)) return false;
for (int index = 0; index < m_elfHdr.e_shnum; index ++) { for (int index = 0; index < m_elfHdr.e_shnum; index ++) {
if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) { if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) {
m_status = Decoder::file_invalid; m_status = NullDecoder::file_invalid;
return false; return false;
} }
// string table // string table
if (shdr.sh_type == SHT_STRTAB) { if (shdr.sh_type == SHT_STRTAB) {
ElfStringTable* table = new (std::nothrow) ElfStringTable(m_file, shdr, index); ElfStringTable* table = new (std::nothrow) ElfStringTable(m_file, shdr, index);
if (table == NULL) { if (table == NULL) {
m_status = Decoder::out_of_memory; m_status = NullDecoder::out_of_memory;
return false; return false;
} }
add_string_table(table); add_string_table(table);
} else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { } else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
ElfSymbolTable* table = new (std::nothrow) ElfSymbolTable(m_file, shdr); ElfSymbolTable* table = new (std::nothrow) ElfSymbolTable(m_file, shdr);
if (table == NULL) { if (table == NULL) {
m_status = Decoder::out_of_memory; m_status = NullDecoder::out_of_memory;
return false; return false;
} }
add_symbol_table(table); add_symbol_table(table);
...@@ -140,32 +140,33 @@ bool ElfFile::load_tables() { ...@@ -140,32 +140,33 @@ bool ElfFile::load_tables() {
return true; return true;
} }
const char* ElfFile::decode(address addr, int* offset) { bool ElfFile::decode(address addr, char* buf, int buflen, int* offset) {
// something already went wrong, just give up // something already went wrong, just give up
if (m_status != Decoder::no_error) { if (NullDecoder::is_error(m_status)) {
return NULL; return false;
} }
ElfSymbolTable* symbol_table = m_symbol_tables; ElfSymbolTable* symbol_table = m_symbol_tables;
int string_table_index; int string_table_index;
int pos_in_string_table; int pos_in_string_table;
int off = INT_MAX; int off = INT_MAX;
bool found_symbol = false; bool found_symbol = false;
while (symbol_table != NULL) { while (symbol_table != NULL) {
if (Decoder::no_error == 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)) {
found_symbol = true; found_symbol = true;
} }
symbol_table = symbol_table->m_next; symbol_table = symbol_table->m_next;
} }
if (!found_symbol) return NULL; if (!found_symbol) return false;
ElfStringTable* string_table = get_string_table(string_table_index); ElfStringTable* string_table = get_string_table(string_table_index);
if (string_table == NULL) { if (string_table == NULL) {
m_status = Decoder::file_invalid; m_status = NullDecoder::file_invalid;
return NULL; return false;
} }
if (offset) *offset = off; if (offset) *offset = off;
return string_table->string_at(pos_in_string_table);
return string_table->string_at(pos_in_string_table, buf, buflen);
} }
......
/* /*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
* *
*/ */
#ifndef __ELF_FILE_HPP #ifndef SHARE_VM_UTILITIES_ELF_FILE_HPP
#define __ELF_FILE_HPP #define SHARE_VM_UTILITIES_ELF_FILE_HPP
#if !defined(_WINDOWS) && !defined(__APPLE__) #if !defined(_WINDOWS) && !defined(__APPLE__)
...@@ -83,12 +83,12 @@ class ElfSymbolTable; ...@@ -83,12 +83,12 @@ class ElfSymbolTable;
// part of code to be very defensive, and bait out if anything went wrong. // part of code to be very defensive, and bait out if anything went wrong.
class ElfFile: public CHeapObj { class ElfFile: public CHeapObj {
friend class Decoder; friend class ElfDecoder;
public: public:
ElfFile(const char* filepath); ElfFile(const char* filepath);
~ElfFile(); ~ElfFile();
const char* decode(address addr, int* offset); bool decode(address addr, char* buf, int buflen, int* offset);
const char* filepath() { const char* filepath() {
return m_filepath; return m_filepath;
} }
...@@ -99,7 +99,7 @@ class ElfFile: public CHeapObj { ...@@ -99,7 +99,7 @@ class ElfFile: public CHeapObj {
return (m_filepath && !strcmp(filepath, m_filepath)); return (m_filepath && !strcmp(filepath, m_filepath));
} }
Decoder::decoder_status get_status() { NullDecoder::decoder_status get_status() {
return m_status; return m_status;
} }
...@@ -119,8 +119,9 @@ class ElfFile: public CHeapObj { ...@@ -119,8 +119,9 @@ class ElfFile: public CHeapObj {
// return a string table at specified section index // return a string table at specified section index
ElfStringTable* get_string_table(int index); ElfStringTable* get_string_table(int index);
// look up an address and return the nearest symbol protected:
const char* look_up(Elf_Shdr shdr, address addr, int* offset); ElfFile* next() const { return m_next; }
void set_next(ElfFile* file) { m_next = file; }
protected: protected:
ElfFile* m_next; ElfFile* m_next;
...@@ -139,9 +140,9 @@ class ElfFile: public CHeapObj { ...@@ -139,9 +140,9 @@ class ElfFile: public CHeapObj {
// string tables // string tables
ElfStringTable* m_string_tables; ElfStringTable* m_string_tables;
Decoder::decoder_status m_status; NullDecoder::decoder_status m_status;
}; };
#endif // _WINDOWS #endif // _WINDOWS
#endif // __ELF_FILE_HPP #endif // SHARE_VM_UTILITIES_ELF_FILE_HPP
...@@ -38,7 +38,7 @@ ElfStringTable::ElfStringTable(FILE* file, Elf_Shdr shdr, int index) { ...@@ -38,7 +38,7 @@ ElfStringTable::ElfStringTable(FILE* file, Elf_Shdr shdr, int index) {
m_index = index; m_index = index;
m_next = NULL; m_next = NULL;
m_file = file; m_file = file;
m_status = Decoder::no_error; m_status = NullDecoder::no_error;
// try to load the string table // try to load the string table
long cur_offset = ftell(file); long cur_offset = ftell(file);
...@@ -48,7 +48,7 @@ ElfStringTable::ElfStringTable(FILE* file, Elf_Shdr shdr, int index) { ...@@ -48,7 +48,7 @@ ElfStringTable::ElfStringTable(FILE* file, Elf_Shdr shdr, int index) {
if (fseek(file, shdr.sh_offset, SEEK_SET) || if (fseek(file, shdr.sh_offset, SEEK_SET) ||
fread((void*)m_table, shdr.sh_size, 1, file) != 1 || fread((void*)m_table, shdr.sh_size, 1, file) != 1 ||
fseek(file, cur_offset, SEEK_SET)) { fseek(file, cur_offset, SEEK_SET)) {
m_status = Decoder::file_invalid; m_status = NullDecoder::file_invalid;
os::free((void*)m_table); os::free((void*)m_table);
m_table = NULL; m_table = NULL;
} }
...@@ -67,22 +67,23 @@ ElfStringTable::~ElfStringTable() { ...@@ -67,22 +67,23 @@ ElfStringTable::~ElfStringTable() {
} }
} }
const char* ElfStringTable::string_at(int pos) { bool ElfStringTable::string_at(int pos, char* buf, int buflen) {
if (m_status != Decoder::no_error) { if (NullDecoder::is_error(m_status)) {
return NULL; return false;
} }
if (m_table != NULL) { if (m_table != NULL) {
return (const char*)(m_table + pos); jio_snprintf(buf, buflen, "%s", (const char*)(m_table + pos));
return true;
} else { } else {
long cur_pos = ftell(m_file); long cur_pos = ftell(m_file);
if (cur_pos == -1 || if (cur_pos == -1 ||
fseek(m_file, m_shdr.sh_offset + pos, SEEK_SET) || fseek(m_file, m_shdr.sh_offset + pos, SEEK_SET) ||
fread(m_symbol, 1, MAX_SYMBOL_LEN, m_file) <= 0 || fread(buf, 1, buflen, m_file) <= 0 ||
fseek(m_file, cur_pos, SEEK_SET)) { fseek(m_file, cur_pos, SEEK_SET)) {
m_status = Decoder::file_invalid; m_status = NullDecoder::file_invalid;
return NULL; return false;
} }
return (const char*)m_symbol; return true;
} }
} }
......
/* /*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
* *
*/ */
#ifndef __ELF_STRING_TABLE_HPP #ifndef SHARE_VM_UTILITIES_ELF_STRING_TABLE_HPP
#define __ELF_STRING_TABLE_HPP #define SHARE_VM_UTILITIES_ELF_STRING_TABLE_HPP
#if !defined(_WINDOWS) && !defined(__APPLE__) #if !defined(_WINDOWS) && !defined(__APPLE__)
...@@ -35,9 +35,6 @@ ...@@ -35,9 +35,6 @@
// The string table represents a string table section in an elf file. // The string table represents a string table section in an elf file.
// Whenever there is enough memory, it will load whole string table as // Whenever there is enough memory, it will load whole string table as
// one blob. Otherwise, it will load string from file when requested. // one blob. Otherwise, it will load string from file when requested.
#define MAX_SYMBOL_LEN 256
class ElfStringTable: CHeapObj { class ElfStringTable: CHeapObj {
friend class ElfFile; friend class ElfFile;
public: public:
...@@ -48,10 +45,10 @@ class ElfStringTable: CHeapObj { ...@@ -48,10 +45,10 @@ class ElfStringTable: CHeapObj {
int index() { return m_index; }; int index() { return m_index; };
// get string at specified offset // get string at specified offset
const char* string_at(int offset); bool string_at(int offset, char* buf, int buflen);
// get status code // get status code
Decoder::decoder_status get_status() { return m_status; }; NullDecoder::decoder_status get_status() { return m_status; };
protected: protected:
ElfStringTable* m_next; ElfStringTable* m_next;
...@@ -69,13 +66,10 @@ class ElfStringTable: CHeapObj { ...@@ -69,13 +66,10 @@ class ElfStringTable: CHeapObj {
// section header // section header
Elf_Shdr m_shdr; Elf_Shdr m_shdr;
// buffer for reading individual string
char m_symbol[MAX_SYMBOL_LEN];
// error code // error code
Decoder::decoder_status m_status; NullDecoder::decoder_status m_status;
}; };
#endif // _WINDOWS #endif // _WINDOWS and _APPLE
#endif // __ELF_STRING_TABLE_HPP #endif // SHARE_VM_UTILITIES_ELF_STRING_TABLE_HPP
...@@ -34,7 +34,7 @@ ElfSymbolTable::ElfSymbolTable(FILE* file, Elf_Shdr shdr) { ...@@ -34,7 +34,7 @@ ElfSymbolTable::ElfSymbolTable(FILE* file, Elf_Shdr shdr) {
m_symbols = NULL; m_symbols = NULL;
m_next = NULL; m_next = NULL;
m_file = file; m_file = file;
m_status = Decoder::no_error; m_status = NullDecoder::no_error;
// try to load the string table // try to load the string table
long cur_offset = ftell(file); long cur_offset = ftell(file);
...@@ -45,16 +45,16 @@ ElfSymbolTable::ElfSymbolTable(FILE* file, Elf_Shdr shdr) { ...@@ -45,16 +45,16 @@ ElfSymbolTable::ElfSymbolTable(FILE* file, Elf_Shdr shdr) {
if (fseek(file, shdr.sh_offset, SEEK_SET) || if (fseek(file, shdr.sh_offset, SEEK_SET) ||
fread((void*)m_symbols, shdr.sh_size, 1, file) != 1 || fread((void*)m_symbols, shdr.sh_size, 1, file) != 1 ||
fseek(file, cur_offset, SEEK_SET)) { fseek(file, cur_offset, SEEK_SET)) {
m_status = Decoder::file_invalid; m_status = NullDecoder::file_invalid;
os::free(m_symbols); os::free(m_symbols);
m_symbols = NULL; m_symbols = NULL;
} }
} }
if (m_status == Decoder::no_error) { if (!NullDecoder::is_error(m_status)) {
memcpy(&m_shdr, &shdr, sizeof(Elf_Shdr)); memcpy(&m_shdr, &shdr, sizeof(Elf_Shdr));
} }
} else { } else {
m_status = Decoder::file_invalid; m_status = NullDecoder::file_invalid;
} }
} }
...@@ -68,13 +68,13 @@ ElfSymbolTable::~ElfSymbolTable() { ...@@ -68,13 +68,13 @@ ElfSymbolTable::~ElfSymbolTable() {
} }
} }
Decoder::decoder_status ElfSymbolTable::lookup(address addr, int* stringtableIndex, int* posIndex, int* offset) { bool ElfSymbolTable::lookup(address addr, int* stringtableIndex, int* posIndex, int* offset) {
assert(stringtableIndex, "null string table index pointer"); assert(stringtableIndex, "null string table index pointer");
assert(posIndex, "null string table offset pointer"); assert(posIndex, "null string table offset pointer");
assert(offset, "null offset pointer"); assert(offset, "null offset pointer");
if (m_status != Decoder::no_error) { if (NullDecoder::is_error(m_status)) {
return m_status; return false;
} }
address pc = 0; address pc = 0;
...@@ -97,8 +97,8 @@ Decoder::decoder_status ElfSymbolTable::lookup(address addr, int* stringtableInd ...@@ -97,8 +97,8 @@ Decoder::decoder_status ElfSymbolTable::lookup(address addr, int* stringtableInd
long cur_pos; long cur_pos;
if ((cur_pos = ftell(m_file)) == -1 || if ((cur_pos = ftell(m_file)) == -1 ||
fseek(m_file, m_shdr.sh_offset, SEEK_SET)) { fseek(m_file, m_shdr.sh_offset, SEEK_SET)) {
m_status = Decoder::file_invalid; m_status = NullDecoder::file_invalid;
return m_status; return false;
} }
Elf_Sym sym; Elf_Sym sym;
...@@ -114,13 +114,13 @@ Decoder::decoder_status ElfSymbolTable::lookup(address addr, int* stringtableInd ...@@ -114,13 +114,13 @@ Decoder::decoder_status ElfSymbolTable::lookup(address addr, int* stringtableInd
} }
} }
} else { } else {
m_status = Decoder::file_invalid; m_status = NullDecoder::file_invalid;
return m_status; return false;
} }
} }
fseek(m_file, cur_pos, SEEK_SET); fseek(m_file, cur_pos, SEEK_SET);
} }
return m_status; return true;
} }
#endif // _WINDOWS #endif // _WINDOWS
/* /*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
* *
*/ */
#ifndef __ELF_SYMBOL_TABLE_HPP #ifndef SHARE_VM_UTILITIES_ELF_SYMBOL_TABLE_HPP
#define __ELF_SYMBOL_TABLE_HPP #define SHARE_VM_UTILITIES_ELF_SYMBOL_TABLE_HPP
#if !defined(_WINDOWS) && !defined(__APPLE__) #if !defined(_WINDOWS) && !defined(__APPLE__)
...@@ -45,9 +45,9 @@ class ElfSymbolTable: public CHeapObj { ...@@ -45,9 +45,9 @@ class ElfSymbolTable: public CHeapObj {
~ElfSymbolTable(); ~ElfSymbolTable();
// search the symbol that is nearest to the specified address. // search the symbol that is nearest to the specified address.
Decoder::decoder_status lookup(address addr, int* stringtableIndex, int* posIndex, int* offset); bool lookup(address addr, int* stringtableIndex, int* posIndex, int* offset);
Decoder::decoder_status get_status() { return m_status; }; NullDecoder::decoder_status get_status() { return m_status; };
protected: protected:
ElfSymbolTable* m_next; ElfSymbolTable* m_next;
...@@ -62,9 +62,9 @@ class ElfSymbolTable: public CHeapObj { ...@@ -62,9 +62,9 @@ class ElfSymbolTable: public CHeapObj {
// section header // section header
Elf_Shdr m_shdr; Elf_Shdr m_shdr;
Decoder::decoder_status m_status; NullDecoder::decoder_status m_status;
}; };
#endif // _WINDOWS #endif // _WINDOWS and _APPLE
#endif // __ELF_SYMBOL_TABLE_HPP #endif // SHARE_VM_UTILITIES_ELF_SYMBOL_TABLE_HPP
...@@ -571,8 +571,6 @@ void VMError::report(outputStream* st) { ...@@ -571,8 +571,6 @@ void VMError::report(outputStream* st) {
if (fr.pc()) { if (fr.pc()) {
st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)"); 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; int count = 0;
while (count++ < StackPrintLimit) { while (count++ < StackPrintLimit) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册