提交 72780398 编写于 作者: Z zgu

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
上级 75e08dfa
...@@ -106,17 +106,17 @@ ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \>= 505), 1) ...@@ -106,17 +106,17 @@ ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \>= 505), 1)
# Not sure what the 'designed for' comment is referring too above. # Not sure what the 'designed for' comment is referring too above.
# The order may not be too significant anymore, but I have placed this # 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. # 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 else
ifeq ($(COMPILER_REV_NUMERIC), 502) ifeq ($(COMPILER_REV_NUMERIC), 502)
# SC6.1 has it's own libm.so: specifying anything else provokes a name conflict. # 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 else
LIBS += -ldl -lthread -lsocket $(LIBM) -lsched -ldoor LIBS += -ldl -lthread -lsocket $(LIBM) -lsched -ldoor -ldemangle
endif # 502 endif # 502
endif # 505 endif # 505
else else
LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc -ldemangle
endif # sparcWorks endif # sparcWorks
# By default, link the *.o into the library, not the executable. # By default, link the *.o into the library, not the executable.
......
/*
* 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;
}
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
#include "services/attachListener.hpp" #include "services/attachListener.hpp"
#include "services/runtimeService.hpp" #include "services/runtimeService.hpp"
#include "thread_linux.inline.hpp" #include "thread_linux.inline.hpp"
#include "utilities/decoder.hpp"
#include "utilities/defaultStream.hpp" #include "utilities/defaultStream.hpp"
#include "utilities/events.hpp" #include "utilities/events.hpp"
#include "utilities/growableArray.hpp" #include "utilities/growableArray.hpp"
...@@ -1671,14 +1672,23 @@ bool os::dll_address_to_function_name(address addr, char *buf, ...@@ -1671,14 +1672,23 @@ bool os::dll_address_to_function_name(address addr, char *buf,
Dl_info dlinfo; Dl_info dlinfo;
if (dladdr((void*)addr, &dlinfo) && dlinfo.dli_sname != NULL) { if (dladdr((void*)addr, &dlinfo) && dlinfo.dli_sname != NULL) {
if (buf) jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname); if (buf != NULL) {
if (offset) *offset = addr - (address)dlinfo.dli_saddr; 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; return true;
} else { } else if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) {
if (buf) buf[0] = '\0'; if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
if (offset) *offset = -1; dlinfo.dli_fname, buf, buflen, offset) == Decoder::no_error) {
return false; return true;
}
} }
if (buf != NULL) buf[0] = '\0';
if (offset != NULL) *offset = -1;
return false;
} }
struct _address_to_library_name { struct _address_to_library_name {
......
/*
* 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);
}
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#include "services/attachListener.hpp" #include "services/attachListener.hpp"
#include "services/runtimeService.hpp" #include "services/runtimeService.hpp"
#include "thread_solaris.inline.hpp" #include "thread_solaris.inline.hpp"
#include "utilities/decoder.hpp"
#include "utilities/defaultStream.hpp" #include "utilities/defaultStream.hpp"
#include "utilities/events.hpp" #include "utilities/events.hpp"
#include "utilities/growableArray.hpp" #include "utilities/growableArray.hpp"
...@@ -1967,28 +1968,43 @@ bool os::dll_address_to_function_name(address addr, char *buf, ...@@ -1967,28 +1968,43 @@ bool os::dll_address_to_function_name(address addr, char *buf,
Sym * info; Sym * info;
if (dladdr1_func((void *)addr, &dlinfo, (void **)&info, if (dladdr1_func((void *)addr, &dlinfo, (void **)&info,
RTLD_DL_SYMENT)) { RTLD_DL_SYMENT)) {
if (buf) jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname); if ((char *)dlinfo.dli_saddr + info->st_size > (char *)addr) {
if (offset) *offset = addr - (address)dlinfo.dli_saddr; if (buf != NULL) {
if (!Decoder::demangle(dlinfo.dli_sname, buf, buflen))
// check if the returned symbol really covers addr jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
return ((char *)dlinfo.dli_saddr + info->st_size > (char *)addr); }
} else { if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
if (buf) buf[0] = '\0'; return true;
if (offset) *offset = -1; }
return false; }
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 { } else {
// no, only dladdr is available // no, only dladdr is available
if(dladdr((void *)addr, &dlinfo)) { if (dladdr((void *)addr, &dlinfo)) {
if (buf) jio_snprintf(buf, buflen, dlinfo.dli_sname); if (buf != NULL) {
if (offset) *offset = addr - (address)dlinfo.dli_saddr; 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; 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;
}
} }
bool os::dll_address_to_library_name(address addr, char* buf, bool os::dll_address_to_library_name(address addr, char* buf,
......
/*
* 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);
}
...@@ -63,6 +63,7 @@ ...@@ -63,6 +63,7 @@
#include "services/attachListener.hpp" #include "services/attachListener.hpp"
#include "services/runtimeService.hpp" #include "services/runtimeService.hpp"
#include "thread_windows.inline.hpp" #include "thread_windows.inline.hpp"
#include "utilities/decoder.hpp"
#include "utilities/defaultStream.hpp" #include "utilities/defaultStream.hpp"
#include "utilities/events.hpp" #include "utilities/events.hpp"
#include "utilities/growableArray.hpp" #include "utilities/growableArray.hpp"
...@@ -1369,12 +1370,11 @@ bool os::dll_address_to_library_name(address addr, char* buf, ...@@ -1369,12 +1370,11 @@ 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) {
// Unimplemented on Windows - in order to use SymGetSymFromAddr(), if (Decoder::decode(addr, buf, buflen, offset) == Decoder::no_error) {
// we need to initialize imagehlp/dbghelp, then load symbol table return true;
// 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 != NULL) *offset = -1;
if (offset) *offset = -1; if (buf != NULL) buf[0] = '\0';
if (buf) buf[0] = '\0';
return false; return false;
} }
......
...@@ -41,6 +41,8 @@ ...@@ -41,6 +41,8 @@
#include "runtime/signature.hpp" #include "runtime/signature.hpp"
#include "runtime/stubCodeGenerator.hpp" #include "runtime/stubCodeGenerator.hpp"
#include "runtime/stubRoutines.hpp" #include "runtime/stubRoutines.hpp"
#include "utilities/decoder.hpp"
#ifdef TARGET_ARCH_x86 #ifdef TARGET_ARCH_x86
# include "nativeInst_x86.hpp" # include "nativeInst_x86.hpp"
#endif #endif
...@@ -652,7 +654,7 @@ static void print_C_frame(outputStream* st, char* buf, int buflen, address pc) { ...@@ -652,7 +654,7 @@ static void print_C_frame(outputStream* st, char* buf, int buflen, address pc) {
// names if pc is within jvm.dll or libjvm.so, because JVM only has // 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 // JVM_xxxx and a few other symbols in the dynamic symbol table. Do this
// only for native libraries. // 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); found = os::dll_address_to_function_name(pc, buf, buflen, &offset);
if (found) { if (found) {
......
/*
* 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
/*
* 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
/*
* 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
/*
* 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
/*
* 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
/*
* 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
/*
* 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
/*
* 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
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "runtime/vmThread.hpp" #include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp" #include "runtime/vm_operations.hpp"
#include "utilities/debug.hpp" #include "utilities/debug.hpp"
#include "utilities/decoder.hpp"
#include "utilities/defaultStream.hpp" #include "utilities/defaultStream.hpp"
#include "utilities/top.hpp" #include "utilities/top.hpp"
#include "utilities/vmError.hpp" #include "utilities/vmError.hpp"
...@@ -516,8 +517,10 @@ void VMError::report(outputStream* st) { ...@@ -516,8 +517,10 @@ 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)");
int count = 0; // initialize decoder to decode C frames
Decoder decoder;
int count = 0;
while (count++ < StackPrintLimit) { while (count++ < StackPrintLimit) {
fr.print_on_error(st, buf, sizeof(buf)); fr.print_on_error(st, buf, sizeof(buf));
st->cr(); st->cr();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册