提交 0847f212 编写于 作者: J jrose

6667042: PrintAssembly option does not work without special plugin

Summary: remove old private plugin interface, simplify, rework old plugin to use unchanged Gnu sources
Reviewed-by: kvn, rasbold
上级 c72f307a
......@@ -168,3 +168,4 @@
^build/linux/export-linux-x64/
^dist/
^nbproject/private/
^src/share/tools/hsdis/bin/
......@@ -71,6 +71,7 @@ endif
# The following variables are defined in the generated flags.make file.
BUILD_VERSION = -DHOTSPOT_RELEASE_VERSION="\"$(HS_BUILD_VER)\""
JRE_VERSION = -DJRE_RELEASE_VERSION="\"$(JRE_RELEASE_VER)\""
HS_LIB_ARCH = -DHOTSPOT_LIB_ARCH=\"$(LIBARCH)\"
BUILD_TARGET = -DHOTSPOT_BUILD_TARGET="\"$(TARGET)\""
BUILD_USER = -DHOTSPOT_BUILD_USER="\"$(HOTSPOT_BUILD_USER)\""
VM_DISTRO = -DHOTSPOT_VM_DISTRO="\"$(HOTSPOT_VM_DISTRO)\""
......@@ -81,6 +82,7 @@ CPPFLAGS = \
${BUILD_VERSION} \
${BUILD_TARGET} \
${BUILD_USER} \
${HS_LIB_ARCH} \
${JRE_VERSION} \
${VM_DISTRO}
......
......@@ -12,6 +12,4 @@ lib_arch = amd64
compiler = gcc
gnu_dis_arch = amd64
sysdefs = -DLINUX -D_GNU_SOURCE -DAMD64
......@@ -12,6 +12,4 @@ lib_arch = i386
compiler = gcc
gnu_dis_arch = i386
sysdefs = -DLINUX -D_GNU_SOURCE -DIA32
......@@ -12,6 +12,4 @@ lib_arch = sparc
compiler = gcc
gnu_dis_arch = sparc
sysdefs = -DLINUX -D_GNU_SOURCE -DSPARC
......@@ -63,6 +63,7 @@ endif
# The following variables are defined in the generated flags.make file.
BUILD_VERSION = -DHOTSPOT_RELEASE_VERSION="\"$(HS_BUILD_VER)\""
JRE_VERSION = -DJRE_RELEASE_VERSION="\"$(JRE_RELEASE_VER)\""
HS_LIB_ARCH = -DHOTSPOT_LIB_ARCH=\"$(LIBARCH)\"
BUILD_TARGET = -DHOTSPOT_BUILD_TARGET="\"$(TARGET)\""
BUILD_USER = -DHOTSPOT_BUILD_USER="\"$(HOTSPOT_BUILD_USER)\""
VM_DISTRO = -DHOTSPOT_VM_DISTRO="\"$(HOTSPOT_VM_DISTRO)\""
......@@ -73,6 +74,7 @@ CPPFLAGS = \
${BUILD_VERSION} \
${BUILD_TARGET} \
${BUILD_USER} \
${HS_LIB_ARCH} \
${JRE_VERSION} \
${VM_DISTRO}
......
......@@ -12,6 +12,4 @@ lib_arch = amd64
compiler = sparcWorks
gnu_dis_arch = amd64
sysdefs = -DSOLARIS -DSPARC_WORKS -DAMD64
......@@ -12,6 +12,4 @@ lib_arch = amd64
compiler = gcc
gnu_dis_arch = amd64
sysdefs = -DSOLARIS -D_GNU_SOURCE -DAMD64
......@@ -12,6 +12,4 @@ lib_arch = i386
compiler = sparcWorks
gnu_dis_arch = i386
sysdefs = -DSOLARIS -DSPARC_WORKS -DIA32
......@@ -12,6 +12,4 @@ lib_arch = i386
compiler = gcc
gnu_dis_arch = i386
sysdefs = -DSOLARIS -D_GNU_SOURCE -DIA32
......@@ -12,6 +12,4 @@ lib_arch = sparc
compiler = sparcWorks
gnu_dis_arch = sparc
sysdefs = -DSOLARIS -DSPARC_WORKS -DSPARC
......@@ -12,6 +12,4 @@ lib_arch = sparc
compiler = gcc
gnu_dis_arch = sparc
sysdefs = -DSOLARIS -D_GNU_SOURCE -DSPARC
......@@ -8,10 +8,8 @@ os_arch = solaris_sparc
os_arch_model = solaris_sparc
lib_arch = sparc
lib_arch = sparcv9
compiler = sparcWorks
gnu_dis_arch = sparc
sysdefs = -DSOLARIS -DSPARC_WORKS -DSPARC
......@@ -8,10 +8,8 @@ os_arch = solaris_sparc
os_arch_model = solaris_sparc
lib_arch = sparc
lib_arch = sparcv9
compiler = gcc
gnu_dis_arch = sparc
sysdefs = -DSOLARIS -D_GNU_SOURCE -DSPARC
......@@ -58,6 +58,7 @@ CPP_FLAGS=$(CPP_FLAGS) /D "COMPILER1" /D "COMPILER2"
# The following variables are defined in the generated local.make file.
CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_RELEASE_VERSION=\"$(HS_BUILD_VER)\""
CPP_FLAGS=$(CPP_FLAGS) /D "JRE_RELEASE_VERSION=\"$(JRE_RELEASE_VER)\""
CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_LIB_ARCH=\"$(BUILDARCH)\""
CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_BUILD_TARGET=\"$(BUILD_FLAVOR)\""
CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_BUILD_USER=\"$(BuildUser)\""
CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_VM_DISTRO=\"$(HOTSPOT_VM_DISTRO)\""
......
......@@ -10,6 +10,6 @@ os_arch = windows_x86
os_arch_model = windows_x86_64
compiler = visCPP
lib_arch = amd64
gnu_dis_arch = amd64
compiler = visCPP
......@@ -10,7 +10,6 @@ os_arch = windows_x86
os_arch_model = windows_x86_32
compiler = visCPP
gnu_dis_arch = i386
lib_arch = i386
compiler = visCPP
/*
* Copyright 1997-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
# include "incls/_precompiled.incl"
# include "incls/_disassembler_sparc.cpp.incl"
#ifndef PRODUCT
#define SPARC_VERSION (VM_Version::v9_instructions_work()? \
(VM_Version::v8_instructions_work()? "" : "9") : "8")
// This routine is in the shared library:
typedef unsigned char* print_insn_sparc_t(unsigned char* start, DisassemblerEnv* env,
const char* sparc_version);
void* Disassembler::_library = NULL;
dll_func Disassembler::_print_insn_sparc = NULL;
bool Disassembler::load_library() {
if (_library == NULL) {
char buf[1024];
char ebuf[1024];
sprintf(buf, "disassembler%s", os::dll_file_extension());
_library = hpi::dll_load(buf, ebuf, sizeof ebuf);
if (_library != NULL) {
tty->print_cr("Loaded disassembler");
_print_insn_sparc = CAST_TO_FN_PTR(dll_func, hpi::dll_lookup(_library, "print_insn_sparc"));
}
}
return (_library != NULL) && (_print_insn_sparc != NULL);
}
class sparc_env : public DisassemblerEnv {
private:
nmethod* code;
outputStream* output;
const char* version;
static void print_address(address value, outputStream* st);
public:
sparc_env(nmethod* rcode, outputStream* routput) {
code = rcode;
output = routput;
version = SPARC_VERSION;
}
const char* sparc_version() { return version; }
void print_label(intptr_t value);
void print_raw(char* str) { output->print_raw(str); }
void print(char* format, ...);
char* string_for_offset(intptr_t value);
char* string_for_constant(unsigned char* pc, intptr_t value, int is_decimal);
};
void sparc_env::print_address(address adr, outputStream* st) {
if (!Universe::is_fully_initialized()) {
st->print(INTPTR_FORMAT, (intptr_t)adr);
return;
}
if (StubRoutines::contains(adr)) {
StubCodeDesc *desc = StubCodeDesc::desc_for(adr);
if (desc == NULL)
desc = StubCodeDesc::desc_for(adr + frame::pc_return_offset);
if (desc == NULL)
st->print("Unknown stub at " INTPTR_FORMAT, adr);
else {
st->print("Stub::%s", desc->name());
if (desc->begin() != adr)
st->print("%+d 0x%p",adr - desc->begin(), adr);
else if (WizardMode) st->print(" " INTPTR_FORMAT, adr);
}
} else {
BarrierSet* bs = Universe::heap()->barrier_set();
if (bs->kind() == BarrierSet::CardTableModRef &&
adr == (address)((CardTableModRefBS*)(bs))->byte_map_base) {
st->print("word_map_base");
if (WizardMode) st->print(" " INTPTR_FORMAT, (intptr_t)adr);
} else {
st->print(INTPTR_FORMAT, (intptr_t)adr);
}
}
}
// called by the disassembler to print out jump addresses
void sparc_env::print_label(intptr_t value) {
print_address((address) value, output);
}
void sparc_env::print(char* format, ...) {
va_list ap;
va_start(ap, format);
output->vprint(format, ap);
va_end(ap);
}
char* sparc_env::string_for_offset(intptr_t value) {
stringStream st;
print_address((address) value, &st);
return st.as_string();
}
char* sparc_env::string_for_constant(unsigned char* pc, intptr_t value, int is_decimal) {
stringStream st;
oop obj;
if (code && (obj = code->embeddedOop_at(pc)) != NULL) {
obj->print_value_on(&st);
} else
{
print_address((address) value, &st);
}
return st.as_string();
}
address Disassembler::decode_instruction(address start, DisassemblerEnv* env) {
const char* version = ((sparc_env*)env)->sparc_version();
return ((print_insn_sparc_t*) _print_insn_sparc)(start, env, version);
}
const int show_bytes = false; // for disassembler debugging
void Disassembler::decode(CodeBlob* cb, outputStream* st) {
st = st ? st : tty;
st->print_cr("Decoding CodeBlob " INTPTR_FORMAT, cb);
decode(cb->instructions_begin(), cb->instructions_end(), st);
}
void Disassembler::decode(u_char* begin, u_char* end, outputStream* st) {
assert ((((intptr_t)begin | (intptr_t)end) % sizeof(int) == 0), "misaligned insn addr");
st = st ? st : tty;
if (!load_library()) {
st->print_cr("Could not load disassembler");
return;
}
sparc_env env(NULL, st);
unsigned char* p = (unsigned char*) begin;
CodeBlob* cb = CodeCache::find_blob_unsafe(begin);
while (p < (unsigned char*) end && p) {
if (cb != NULL) {
cb->print_block_comment(st, (intptr_t)(p - cb->instructions_begin()));
}
unsigned char* p0 = p;
st->print(INTPTR_FORMAT ": ", p);
p = decode_instruction(p, &env);
if (show_bytes && p) {
st->print("\t\t\t");
while (p0 < p) { st->print("%08lx ", *(int*)p0); p0 += sizeof(int); }
}
st->cr();
}
}
void Disassembler::decode(nmethod* nm, outputStream* st) {
st = st ? st : tty;
st->print_cr("Decoding compiled method " INTPTR_FORMAT ":", nm);
st->print("Code:");
st->cr();
if (!load_library()) {
st->print_cr("Could not load disassembler");
return;
}
sparc_env env(nm, st);
unsigned char* p = nm->instructions_begin();
unsigned char* end = nm->instructions_end();
assert ((((intptr_t)p | (intptr_t)end) % sizeof(int) == 0), "misaligned insn addr");
unsigned char *p1 = p;
int total_bucket_count = 0;
while (p1 < end && p1) {
unsigned char *p0 = p1;
++p1;
address bucket_pc = FlatProfiler::bucket_start_for(p1);
if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p1)
total_bucket_count += FlatProfiler::bucket_count_for(p0);
}
while (p < end && p) {
if (p == nm->entry_point()) st->print_cr("[Entry Point]");
if (p == nm->verified_entry_point()) st->print_cr("[Verified Entry Point]");
if (p == nm->exception_begin()) st->print_cr("[Exception Handler]");
if (p == nm->stub_begin()) st->print_cr("[Stub Code]");
if (p == nm->consts_begin()) st->print_cr("[Constants]");
nm->print_block_comment(st, (intptr_t)(p - nm->instructions_begin()));
unsigned char* p0 = p;
st->print(" " INTPTR_FORMAT ": ", p);
p = decode_instruction(p, &env);
nm->print_code_comment_on(st, 40, p0, p);
st->cr();
// Output pc bucket ticks if we have any
address bucket_pc = FlatProfiler::bucket_start_for(p);
if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p) {
int bucket_count = FlatProfiler::bucket_count_for(p0);
tty->print_cr("%3.1f%% [%d]", bucket_count*100.0/total_bucket_count, bucket_count);
tty->cr();
}
}
}
#endif // PRODUCT
/*
* Copyright 1997-1999 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2008 Sun Microsystems, Inc. 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
......@@ -22,30 +22,11 @@
*
*/
// The disassembler prints out sparc code annotated
// with Java specific information.
static int pd_instruction_alignment() {
return sizeof(int);
}
class Disassembler {
#ifndef PRODUCT
private:
// points to the library.
static void* _library;
// points to the print_insn_sparc function.
static dll_func _print_insn_sparc;
// tries to load library and return whether it succedded.
static bool load_library();
// decodes one instruction and return the start of the next instruction.
static address decode_instruction(address start, DisassemblerEnv* env);
#endif
public:
static void decode(CodeBlob *cb, outputStream* st = NULL) PRODUCT_RETURN;
static void decode(nmethod* nm, outputStream* st = NULL) PRODUCT_RETURN;
static void decode(u_char* begin, u_char* end, outputStream* st = NULL) PRODUCT_RETURN;
};
//Reconciliation History
// 1.9 98/04/29 10:45:51 disassembler_i486.hpp
// 1.10 98/05/11 16:47:20 disassembler_i486.hpp
// 1.12 99/06/22 16:37:37 disassembler_i486.hpp
// 1.13 99/08/06 10:09:04 disassembler_i486.hpp
//End
static const char* pd_cpu_opts() {
return (VM_Version::v9_instructions_work()?
(VM_Version::v8_instructions_work()? "" : "v9only") : "v8only");
}
/*
* Copyright 1997-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
# include "incls/_precompiled.incl"
# include "incls/_disassembler_x86.cpp.incl"
#ifndef PRODUCT
void* Disassembler::_library = NULL;
Disassembler::decode_func Disassembler::_decode_instruction = NULL;
bool Disassembler::load_library() {
if (_library == NULL) {
char buf[1024];
char ebuf[1024];
sprintf(buf, "disassembler%s", os::dll_file_extension());
_library = hpi::dll_load(buf, ebuf, sizeof ebuf);
if (_library != NULL) {
tty->print_cr("Loaded disassembler");
_decode_instruction = CAST_TO_FN_PTR(Disassembler::decode_func, hpi::dll_lookup(_library, "decode_instruction"));
}
}
return (_library != NULL) && (_decode_instruction != NULL);
}
class x86_env : public DisassemblerEnv {
private:
nmethod* code;
outputStream* output;
public:
x86_env(nmethod* rcode, outputStream* routput) {
code = rcode;
output = routput;
}
void print_label(intptr_t value);
void print_raw(char* str) { output->print_raw(str); }
void print(char* format, ...);
char* string_for_offset(intptr_t value);
char* string_for_constant(unsigned char* pc, intptr_t value, int is_decimal);
};
void x86_env::print_label(intptr_t value) {
if (!Universe::is_fully_initialized()) {
output->print(INTPTR_FORMAT, value);
return;
}
address adr = (address) value;
if (StubRoutines::contains(adr)) {
StubCodeDesc* desc = StubCodeDesc::desc_for(adr);
const char * desc_name = "unknown stub";
if (desc != NULL) {
desc_name = desc->name();
}
output->print("Stub::%s", desc_name);
if (WizardMode) output->print(" " INTPTR_FORMAT, value);
} else {
output->print(INTPTR_FORMAT, value);
}
}
void x86_env::print(char* format, ...) {
va_list ap;
va_start(ap, format);
output->vprint(format, ap);
va_end(ap);
}
char* x86_env::string_for_offset(intptr_t value) {
stringStream st;
if (!Universe::is_fully_initialized()) {
st.print(INTX_FORMAT, value);
return st.as_string();
}
BarrierSet* bs = Universe::heap()->barrier_set();
BarrierSet::Name bsn = bs->kind();
if (bs->kind() == BarrierSet::CardTableModRef &&
(jbyte*) value == ((CardTableModRefBS*)(bs))->byte_map_base) {
st.print("word_map_base");
} else {
st.print(INTX_FORMAT, value);
}
return st.as_string();
}
char* x86_env::string_for_constant(unsigned char* pc, intptr_t value, int is_decimal) {
stringStream st;
oop obj = NULL;
if (code && ((obj = code->embeddedOop_at(pc)) != NULL)) {
obj->print_value_on(&st);
} else {
if (is_decimal == 1) {
st.print(INTX_FORMAT, value);
} else {
st.print(INTPTR_FORMAT, value);
}
}
return st.as_string();
}
address Disassembler::decode_instruction(address start, DisassemblerEnv* env) {
return ((decode_func) _decode_instruction)(start, env);
}
void Disassembler::decode(CodeBlob* cb, outputStream* st) {
st = st ? st : tty;
st->print_cr("Decoding CodeBlob " INTPTR_FORMAT, cb);
decode(cb->instructions_begin(), cb->instructions_end(), st);
}
void Disassembler::decode(u_char* begin, u_char* end, outputStream* st) {
st = st ? st : tty;
const int show_bytes = false; // for disassembler debugging
if (!load_library()) {
st->print_cr("Could not load disassembler");
return;
}
x86_env env(NULL, st);
unsigned char* p = (unsigned char*) begin;
CodeBlob* cb = CodeCache::find_blob_unsafe(begin);
while (p < (unsigned char*) end) {
if (cb != NULL) {
cb->print_block_comment(st, (intptr_t)(p - cb->instructions_begin()));
}
unsigned char* p0 = p;
st->print(" " INTPTR_FORMAT ": ", p);
p = decode_instruction(p, &env);
if (show_bytes) {
st->print("\t\t\t");
while (p0 < p) st->print("%x ", *p0++);
}
st->cr();
}
}
void Disassembler::decode(nmethod* nm, outputStream* st) {
st = st ? st : tty;
st->print_cr("Decoding compiled method " INTPTR_FORMAT ":", nm);
st->print("Code:");
st->cr();
if (!load_library()) {
st->print_cr("Could not load disassembler");
return;
}
x86_env env(nm, st);
unsigned char* p = nm->instructions_begin();
unsigned char* end = nm->instructions_end();
while (p < end) {
if (p == nm->entry_point()) st->print_cr("[Entry Point]");
if (p == nm->verified_entry_point()) st->print_cr("[Verified Entry Point]");
if (p == nm->exception_begin()) st->print_cr("[Exception Handler]");
if (p == nm->stub_begin()) st->print_cr("[Stub Code]");
if (p == nm->consts_begin()) st->print_cr("[Constants]");
nm->print_block_comment(st, (intptr_t)(p - nm->instructions_begin()));
unsigned char* p0 = p;
st->print(" " INTPTR_FORMAT ": ", p);
p = decode_instruction(p, &env);
nm->print_code_comment_on(st, 40, p0, p);
st->cr();
// Output pc bucket ticks if we have any
address bucket_pc = FlatProfiler::bucket_start_for(p);
if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p) {
int bucket_count = FlatProfiler::bucket_count_for(bucket_pc);
tty->print_cr("[%d]", bucket_count);
}
}
}
#endif // PRODUCT
/*
* Copyright 1997-1999 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2008 Sun Microsystems, Inc. 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
......@@ -22,24 +22,10 @@
*
*/
// The disassembler prints out intel 386 code annotated
// with Java specific information.
static int pd_instruction_alignment() {
return 1;
}
class Disassembler {
#ifndef PRODUCT
private:
typedef address (*decode_func)(address start, DisassemblerEnv* env);
// points the library.
static void* _library;
// points to the decode function.
static decode_func _decode_instruction;
// tries to load library and return whether it succedded.
static bool load_library();
// decodes one instruction and return the start of the next instruction.
static address decode_instruction(address start, DisassemblerEnv* env);
#endif
public:
static void decode(CodeBlob *cb, outputStream* st = NULL) PRODUCT_RETURN;
static void decode(nmethod* nm, outputStream* st = NULL) PRODUCT_RETURN;
static void decode(u_char* begin, u_char* end, outputStream* st = NULL) PRODUCT_RETURN;
};
static const char* pd_cpu_opts() {
return "";
}
#
# Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
# CA 95054 USA or visit www.sun.com if you need additional information or
# have any questions.
#
#
# Single gnu makefile for solaris, linux and windows (windows requires mks or
# cygwin).
ifeq ($(BINUTILS),)
# Pop all the way out of the workspace to look for binutils.
# ...You probably want to override this setting.
BINUTILS = $(shell cd ../../../../..;pwd)/binutils-2.17-$(LIBARCH)
endif
# Default arch; it is changed below as needed.
ARCH = i386
OS = $(shell uname)
CPPFLAGS += -I$(BINUTILS)/include -I$(BINUTILS)/bfd
CPPFLAGS += -DHOTSPOT_LIB_ARCH=\"$(LIBARCH)\" -DLIBARCH_$(LIBARCH)
CPPFLAGS += -DHOTSPOT_OS=\"$(OS)\" -DOS_$(OS)
## OS = SunOS ##
ifeq ($(OS),SunOS)
ARCH = $(shell uname -p)
OS = solaris
CC = cc
CCFLAGS += -Kpic -g
CCFLAGS/amd64 += -xarch=amd64
CCFLAGS/sparcv9 += -xarch=v9
CCFLAGS += $(CCFLAGS/$(LIBARCH))
DLDFLAGS += -G
OUTFLAGS += -o $@
LIB_EXT = .so
else
## OS = Linux ##
ifeq ($(OS),Linux)
CPU = $(shell uname -m)
ifeq ($(CPU),ia64)
ARCH = ia64
else
ifeq ($(CPU),x86_64)
CCFLAGS += -fPIC
endif # x86_64
endif # ia64
OS = linux
CC = gcc
CCFLAGS += -O
DLDFLAGS += -shared
OUTFLAGS += -o $@
LIB_EXT = .so
CPPFLAGS += -Iinclude -Iinclude/$(OS)_$(ARCH)/
## OS = Windows ##
else # !SunOS, !Linux => Windows
OS = win
CC = cl
#CPPFLAGS += /D"WIN32" /D"_WINDOWS" /D"DEBUG" /D"NDEBUG"
CCFLAGS += /nologo /MD /W3 /WX /O2 /Fo$(@:.dll=.obj) /Gi-
CCFLAGS += -Iinclude -Iinclude/gnu -Iinclude/$(OS)_$(ARCH)
CCFLAGS += /D"HOTSPOT_LIB_ARCH=\"$(LIBARCH)\""
DLDFLAGS += /dll /subsystem:windows /incremental:no \
/export:decode_instruction
OUTFLAGS += /link /out:$@
LIB_EXT = .dll
endif # Linux
endif # SunOS
LIBARCH = $(ARCH)
ifdef LP64
LIBARCH64/sparc = sparcv9
LIBARCH64/i386 = amd64
LIBARCH64 = $(LIBARCH64/$(ARCH))
ifneq ($(LIBARCH64),)
LIBARCH = $(LIBARCH64)
endif # LIBARCH64/$(ARCH)
endif # LP64
TARGET_DIR = bin/$(OS)
TARGET = $(TARGET_DIR)/hsdis-$(LIBARCH)$(LIB_EXT)
SOURCE = hsdis.c
LIBRARIES = $(BINUTILS)/bfd/libbfd.a \
$(BINUTILS)/opcodes/libopcodes.a \
$(BINUTILS)/libiberty/libiberty.a
DEMO_TARGET = $(TARGET_DIR)/hsdis-demo-$(LIBARCH)
DEMO_SOURCE = hsdis-demo.c
.PHONY: all clean demo both
all: $(TARGET) demo
both: all all64
%64:
$(MAKE) LP64=1 ${@:%64=%}
demo: $(TARGET) $(DEMO_TARGET)
$(LIBRARIES):
@echo "*** Please build binutils first; see ./README: ***"
@sed < ./README '1,/__________/d' | head -20
@echo "..."; exit 1
$(TARGET): $(SOURCE) $(LIBS) $(LIBRARIES) $(TARGET_DIR)
$(CC) $(OUTFLAGS) $(CPPFLAGS) $(CCFLAGS) $(SOURCE) $(DLDFLAGS) $(LIBRARIES)
$(DEMO_TARGET): $(DEMO_SOURCE) $(TARGET) $(TARGET_DIR)
$(CC) $(OUTFLAGS) $(CPPFLAGS) $(CCFLAGS) $(DEMO_SOURCE) $(LDFLAGS)
$(TARGET_DIR):
[ -d $@ ] || mkdir -p $@
clean:
rm -rf $(TARGET_DIR)
Copyright (c) 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
CA 95054 USA or visit www.sun.com if you need additional information or
have any questions.
________________________________________________________________________
'hsdis': A HotSpot plugin for disassembling dynamically generated code.
The files in this directory (Makefile, hsdis.[ch], hsdis-demo.c)
are built independently of the HotSpot JVM.
To use the plugin with a JVM, you need a new version that can load it.
If the product mode of your JVM does not accept -XX:+PrintAssembly,
you do not have a version that is new enough.
* Building
To build this project you need a build of Gnu binutils to link against.
It is known to work with binutils 2.17.
The makefile looks for this build in $BINUTILS, or (if that is not set),
in .../binutils-2.17-$LIBARCH, where LIBARCH (as in HotSpot) is one of
the jre subdirectory keywords i386, amd64, sparc, sparcv9, etc.
To build Gnu binutils, first download a copy of the software:
http://directory.fsf.org/project/binutils/
Unpack the binutils tarball into an empty directory:
chdir ../../../../..
tar -xzf - < ../binutils-2.17.tar.gz
mv binutils-2.17 binutils-2.17-i386 #or binutils-2.17-sparc
cd binutils-2.17-i386
From inside that directory, run configure and make:
( export CFLAGS='-fPIC'
./configure i386-pc-elf )
gnumake
(Leave out or change the argument to configure if not on an i386 system.)
Next, untar again into another empty directory for the LP64 version:
chdir ..
tar -xzf - < ../binutils-2.17.tar.gz
mv binutils-2.17 binutils-2.17-amd64 #or binutils-2.17-sparcv9
cd binutils-2.17-amd64
From inside that directory, run configure for LP64 and make:
( export ac_cv_c_bigendian=no CFLAGS='-m64 -fPIC' LDFLAGS=-m64
./configure amd64-pc-elf )
gnumake
The -fPIC option is needed because the generated code will be
linked into the hsdid-$LIBARCH.so binary. If you miss the
option, the JVM will fail to load the disassembler.
You probably want two builds, one for 32 and one for 64 bits.
To build the 64-bit variation of a platforn, add LP64=1 to
the make command line for hsdis.
So, go back to the hsdis project and build:
chdir .../hsdis
gnumake
gnumake LP64=1
* Installing
Products are named like bin/$OS/hsdis-$LIBARCH.so.
You can install them on your LD_LIBRARY_PATH,
or inside of your JRE next to $LIBARCH/libjvm.so.
Now test:
export LD_LIBRARY_PATH .../hsdis/bin/solaris:$LD_LIBRARY_PATH
dargs='-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly'
dargs=$dargs' -XX:PrintAssemblyOptions=hsdis-print-bytes'
java $dargs -Xbatch CompileCommand=print,*String.hashCode HelloWorld
If the product mode of the JVM does not accept -XX:+PrintAssembly,
you do not have a version new enough to use the hsdis plugin.
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
/* hsdis-demo.c -- dump a range of addresses as native instructions
This demonstrates the protocol required by the HotSpot PrintAssembly option.
*/
#include "hsdis.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
void greet(const char*);
void disassemble(void*, void*);
void end_of_file();
const char* options = NULL;
int raw = 0;
int xml = 0;
int main(int ac, char** av) {
int greeted = 0;
int i;
for (i = 1; i < ac; i++) {
const char* arg = av[i];
if (arg[0] == '-') {
if (!strcmp(arg, "-xml"))
xml ^= 1;
else if (!strcmp(arg, "-raw"))
raw ^= 1;
else if (!strncmp(arg, "-options=", 9))
options = arg+9;
else
{ printf("Usage: %s [-xml] [name...]\n"); exit(2); }
continue;
}
greet(arg);
greeted = 1;
}
if (!greeted)
greet("world");
printf("...And now for something completely different:\n");
disassemble((void*) &main, (void*) &end_of_file);
printf("Cheers!\n");
}
void greet(const char* whom) {
printf("Hello, %s!\n", whom);
}
void end_of_file() { }
/* don't disassemble after this point... */
#include "dlfcn.h"
#ifdef HOTSPOT_LIB_ARCH
#define LIBARCH HOTSPOT_LIB_ARCH
#endif
#ifdef HOTSPOT_OS
#define OS HOTSPOT_OS
#endif
#define DECODE_INSTRUCTIONS_NAME "decode_instructions"
#define HSDIS_NAME "hsdis"
static void* decode_instructions_pv = 0;
static const char* hsdis_path[] = {
HSDIS_NAME".so",
#ifdef OS
"bin/"OS"/"HSDIS_NAME".so",
#endif
#ifdef LIBARCH
HSDIS_NAME"-"LIBARCH".so",
#ifdef OS
"bin/"OS"/"HSDIS_NAME"-"LIBARCH".so",
#endif
#endif
NULL
};
static const char* load_decode_instructions() {
void* dllib = NULL;
const char* *next_in_path = hsdis_path;
while (1) {
decode_instructions_pv = dlsym(dllib, DECODE_INSTRUCTIONS_NAME);
if (decode_instructions_pv != NULL)
return NULL;
if (dllib != NULL)
return "plugin does not defined "DECODE_INSTRUCTIONS_NAME;
for (dllib = NULL; dllib == NULL; ) {
const char* next_lib = (*next_in_path++);
if (next_lib == NULL)
return "cannot find plugin "HSDIS_NAME".so";
dllib = dlopen(next_lib, RTLD_LAZY);
}
}
}
static const char* lookup(void* addr) {
#define CHECK_NAME(fn) \
if (addr == (void*) &fn) return #fn;
CHECK_NAME(main);
CHECK_NAME(greet);
return NULL;
}
/* does the event match the tag, followed by a null, space, or slash? */
#define MATCH(event, tag) \
(!strncmp(event, tag, sizeof(tag)-1) && \
(!event[sizeof(tag)-1] || strchr(" /", event[sizeof(tag)-1])))
static const char event_cookie[] = "event_cookie"; /* demo placeholder */
static void* handle_event(void* cookie, const char* event, void* arg) {
#define NS_DEMO "demo:"
if (cookie != event_cookie)
printf("*** bad event cookie %p != %p\n", cookie, event_cookie);
if (xml) {
/* We could almost do a printf(event, arg),
but for the sake of a better demo,
we dress the result up as valid XML.
*/
const char* fmt = strchr(event, ' ');
int evlen = (fmt ? fmt - event : strlen(event));
if (!fmt) {
if (event[0] != '/') {
printf("<"NS_DEMO"%.*s>", evlen, event);
} else {
printf("</"NS_DEMO"%.*s>", evlen-1, event+1);
}
} else {
if (event[0] != '/') {
printf("<"NS_DEMO"%.*s", evlen, event);
printf(fmt, arg);
printf(">");
} else {
printf("<"NS_DEMO"%.*s_done", evlen-1, event+1);
printf(fmt, arg);
printf("/></"NS_DEMO"%.*s>", evlen-1, event+1);
}
}
}
if (MATCH(event, "insn")) {
const char* name = lookup(arg);
if (name) printf("%s:\n", name);
/* basic action for <insn>: */
printf(" %p\t", arg);
} else if (MATCH(event, "/insn")) {
/* basic action for </insn>:
(none, plugin puts the newline for us
*/
} else if (MATCH(event, "mach")) {
printf("Decoding for CPU '%s'\n", (char*) arg);
} else if (MATCH(event, "addr")) {
/* basic action for <addr/>: */
const char* name = lookup(arg);
if (name) {
printf("&%s (%p)", name, arg);
/* return non-null to notify hsdis not to print the addr */
return arg;
}
}
/* null return is always safe; can mean "I ignored it" */
return NULL;
}
#define fprintf_callback \
(decode_instructions_printf_callback_ftype)&fprintf
void disassemble(void* from, void* to) {
const char* err = load_decode_instructions();
if (err != NULL) {
printf("%s: %s\n", err, dlerror());
exit(1);
}
printf("Decoding from %p to %p...\n", from, to);
decode_instructions_ftype decode_instructions
= (decode_instructions_ftype) decode_instructions_pv;
void* res;
if (raw && xml) {
res = (*decode_instructions)(from, to, NULL, stdout, NULL, stdout, options);
} else if (raw) {
res = (*decode_instructions)(from, to, NULL, NULL, NULL, stdout, options);
} else {
res = (*decode_instructions)(from, to,
handle_event, (void*) event_cookie,
fprintf_callback, stdout,
options);
}
if (res != to)
printf("*** Result was %p!\n", res);
}
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
/* hsdis.c -- dump a range of addresses as native instructions
This implements the plugin protocol required by the
HotSpot PrintAssembly option.
*/
#include "hsdis.h"
#include <sysdep.h>
#include <libiberty.h>
#include <bfd.h>
#include <dis-asm.h>
#ifndef bool
#define bool int
#define true 1
#define false 0
#endif /*bool*/
/* short names for stuff in hsdis.h */
typedef decode_instructions_event_callback_ftype event_callback_t;
typedef decode_instructions_printf_callback_ftype printf_callback_t;
/* disassemble_info.application_data object */
struct hsdis_app_data {
/* the arguments to decode_instructions */
uintptr_t start; uintptr_t end;
event_callback_t event_callback; void* event_stream;
printf_callback_t printf_callback; void* printf_stream;
bool losing;
/* the architecture being disassembled */
const char* arch_name;
const bfd_arch_info_type* arch_info;
/* the disassembler we are going to use: */
disassembler_ftype dfn;
struct disassemble_info dinfo; /* the actual struct! */
char mach_option[64];
char insn_options[256];
};
#define DECL_APP_DATA(dinfo) \
struct hsdis_app_data* app_data = (struct hsdis_app_data*) (dinfo)->application_data
#define DECL_EVENT_CALLBACK(app_data) \
event_callback_t event_callback = (app_data)->event_callback; \
void* event_stream = (app_data)->event_stream
#define DECL_PRINTF_CALLBACK(app_data) \
printf_callback_t printf_callback = (app_data)->printf_callback; \
void* printf_stream = (app_data)->printf_stream
static void print_help(struct hsdis_app_data* app_data,
const char* msg, const char* arg);
static void setup_app_data(struct hsdis_app_data* app_data,
const char* options);
static const char* format_insn_close(const char* close,
disassemble_info* dinfo,
char* buf, size_t bufsize);
void*
#ifdef DLL_ENTRY
DLL_ENTRY
#endif
decode_instructions(void* start_pv, void* end_pv,
event_callback_t event_callback_arg, void* event_stream_arg,
printf_callback_t printf_callback_arg, void* printf_stream_arg,
const char* options) {
struct hsdis_app_data app_data;
memset(&app_data, 0, sizeof(app_data));
app_data.start = (uintptr_t) start_pv;
app_data.end = (uintptr_t) end_pv;
app_data.event_callback = event_callback_arg;
app_data.event_stream = event_stream_arg;
app_data.printf_callback = printf_callback_arg;
app_data.printf_stream = printf_stream_arg;
setup_app_data(&app_data, options);
char buf[128];
{
/* now reload everything from app_data: */
DECL_EVENT_CALLBACK(&app_data);
DECL_PRINTF_CALLBACK(&app_data);
uintptr_t start = app_data.start;
uintptr_t end = app_data.end;
uintptr_t p = start;
(*event_callback)(event_stream, "insns", (void*)start);
(*event_callback)(event_stream, "mach name='%s'",
(void*) app_data.arch_info->printable_name);
if (app_data.dinfo.bytes_per_line != 0) {
(*event_callback)(event_stream, "format bytes-per-line='%p'/",
(void*)(intptr_t) app_data.dinfo.bytes_per_line);
}
while (p < end && !app_data.losing) {
(*event_callback)(event_stream, "insn", (void*) p);
/* reset certain state, so we can read it with confidence */
app_data.dinfo.insn_info_valid = 0;
app_data.dinfo.branch_delay_insns = 0;
app_data.dinfo.data_size = 0;
app_data.dinfo.insn_type = 0;
int size = (*app_data.dfn)((bfd_vma) p, &app_data.dinfo);
if (size > 0) p += size;
else app_data.losing = true;
const char* insn_close = format_insn_close("/insn", &app_data.dinfo,
buf, sizeof(buf));
(*event_callback)(event_stream, insn_close, (void*) p);
/* follow each complete insn by a nice newline */
(*printf_callback)(printf_stream, "\n");
}
(*event_callback)(event_stream, "/insns", (void*) p);
return (void*) p;
}
}
/* take the address of the function, for luck, and also test the typedef: */
const decode_instructions_ftype decode_instructions_address = &decode_instructions;
static const char* format_insn_close(const char* close,
disassemble_info* dinfo,
char* buf, size_t bufsize) {
if (!dinfo->insn_info_valid)
return close;
enum dis_insn_type itype = dinfo->insn_type;
int dsize = dinfo->data_size, delays = dinfo->branch_delay_insns;
if ((itype == dis_nonbranch && (dsize | delays) == 0)
|| (strlen(close) + 3*20 > bufsize))
return close;
const char* type = "unknown";
switch (itype) {
case dis_nonbranch: type = NULL; break;
case dis_branch: type = "branch"; break;
case dis_condbranch: type = "condbranch"; break;
case dis_jsr: type = "jsr"; break;
case dis_condjsr: type = "condjsr"; break;
case dis_dref: type = "dref"; break;
case dis_dref2: type = "dref2"; break;
}
strcpy(buf, close);
char* p = buf;
if (type) sprintf(p += strlen(p), " type='%s'", type);
if (dsize) sprintf(p += strlen(p), " dsize='%d'", dsize);
if (delays) sprintf(p += strlen(p), " delay='%d'", delays);
return buf;
}
/* handler functions */
static int
hsdis_read_memory_func(bfd_vma memaddr,
bfd_byte* myaddr,
unsigned int length,
struct disassemble_info* dinfo) {
uintptr_t memaddr_p = (uintptr_t) memaddr;
DECL_APP_DATA(dinfo);
if (memaddr_p + length > app_data->end) {
/* read is out of bounds */
return EIO;
} else {
memcpy(myaddr, (bfd_byte*) memaddr_p, length);
return 0;
}
}
static void
hsdis_print_address_func(bfd_vma vma, struct disassemble_info* dinfo) {
/* the actual value to print: */
void* addr_value = (void*) (uintptr_t) vma;
DECL_APP_DATA(dinfo);
DECL_EVENT_CALLBACK(app_data);
/* issue the event: */
void* result =
(*event_callback)(event_stream, "addr/", addr_value);
if (result == NULL) {
/* event declined */
generic_print_address(vma, dinfo);
}
}
/* configuration */
static void set_optional_callbacks(struct hsdis_app_data* app_data);
static void parse_caller_options(struct hsdis_app_data* app_data,
const char* caller_options);
static const char* native_arch_name();
static enum bfd_endian native_endian();
static const bfd_arch_info_type* find_arch_info(const char* arch_nane);
static bfd* get_native_bfd(const bfd_arch_info_type* arch_info,
/* to avoid malloc: */
bfd* empty_bfd, bfd_target* empty_xvec);
static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo,
void *stream,
fprintf_ftype fprintf_func,
bfd* bfd,
char* disassembler_options);
static void parse_fake_insn(disassembler_ftype dfn,
struct disassemble_info* dinfo);
static void setup_app_data(struct hsdis_app_data* app_data,
const char* caller_options) {
/* Make reasonable defaults for null callbacks.
A non-null stream for a null callback is assumed to be a FILE* for output.
Events are rendered as XML.
*/
set_optional_callbacks(app_data);
/* Look into caller_options for anything interesting. */
if (caller_options != NULL)
parse_caller_options(app_data, caller_options);
/* Discover which architecture we are going to disassemble. */
app_data->arch_name = &app_data->mach_option[0];
if (app_data->arch_name[0] == '\0')
app_data->arch_name = native_arch_name();
app_data->arch_info = find_arch_info(app_data->arch_name);
/* Make a fake bfd to hold the arch. and byteorder info. */
struct {
bfd_target empty_xvec;
bfd empty_bfd;
} buf;
bfd* native_bfd = get_native_bfd(app_data->arch_info,
/* to avoid malloc: */
&buf.empty_bfd, &buf.empty_xvec);
init_disassemble_info_from_bfd(&app_data->dinfo,
app_data->printf_stream,
app_data->printf_callback,
native_bfd,
app_data->insn_options);
/* Finish linking together the various callback blocks. */
app_data->dinfo.application_data = (void*) app_data;
app_data->dfn = disassembler(native_bfd);
app_data->dinfo.print_address_func = hsdis_print_address_func;
app_data->dinfo.read_memory_func = hsdis_read_memory_func;
if (app_data->dfn == NULL) {
const char* bad = app_data->arch_name;
static bool complained;
if (bad == &app_data->mach_option[0])
print_help(app_data, "bad mach=%s", bad);
else if (!complained)
print_help(app_data, "bad native mach=%s; please port hsdis to this platform", bad);
complained = true;
/* must bail out */
app_data->losing = true;
return;
}
parse_fake_insn(app_data->dfn, &app_data->dinfo);
}
/* ignore all events, return a null */
static void* null_event_callback(void* ignore_stream, const char* ignore_event, void* arg) {
return NULL;
}
/* print all events as XML markup */
static void* xml_event_callback(void* stream, const char* event, void* arg) {
FILE* fp = (FILE*) stream;
#define NS_PFX "dis:"
if (event[0] != '/') {
/* issue the tag, with or without a formatted argument */
fprintf(fp, "<"NS_PFX);
fprintf(fp, event, arg);
fprintf(fp, ">");
} else {
++event; /* skip slash */
const char* argp = strchr(event, ' ');
if (argp == NULL) {
/* no arguments; just issue the closing tag */
fprintf(fp, "</"NS_PFX"%s>", event);
} else {
/* split out the closing attributes as <dis:foo_done attr='val'/> */
int event_prefix = (argp - event);
fprintf(fp, "<"NS_PFX"%.*s_done", event_prefix, event);
fprintf(fp, argp, arg);
fprintf(fp, "/></"NS_PFX"%.*s>", event_prefix, event);
}
}
return NULL;
}
static void set_optional_callbacks(struct hsdis_app_data* app_data) {
if (app_data->printf_callback == NULL) {
int (*fprintf_callback)(FILE*, const char*, ...) = &fprintf;
FILE* fprintf_stream = stdout;
app_data->printf_callback = (printf_callback_t) fprintf_callback;
if (app_data->printf_stream == NULL)
app_data->printf_stream = (void*) fprintf_stream;
}
if (app_data->event_callback == NULL) {
if (app_data->event_stream == NULL)
app_data->event_callback = &null_event_callback;
else
app_data->event_callback = &xml_event_callback;
}
}
static void parse_caller_options(struct hsdis_app_data* app_data, const char* caller_options) {
char* iop_base = app_data->insn_options;
char* iop_limit = iop_base + sizeof(app_data->insn_options) - 1;
char* iop = iop_base;
const char* p;
for (p = caller_options; p != NULL; ) {
const char* q = strchr(p, ',');
size_t plen = (q == NULL) ? strlen(p) : ((q++) - p);
if (plen == 4 && strncmp(p, "help", plen) == 0) {
print_help(app_data, NULL, NULL);
} else if (plen >= 5 && strncmp(p, "mach=", 5) == 0) {
char* mach_option = app_data->mach_option;
size_t mach_size = sizeof(app_data->mach_option);
mach_size -= 1; /*leave room for the null*/
if (plen > mach_size) plen = mach_size;
strncpy(mach_option, p, plen);
mach_option[plen] = '\0';
} else if (plen > 6 && strncmp(p, "hsdis-", 6)) {
// do not pass these to the next level
} else {
/* just copy it; {i386,sparc}-dis.c might like to see it */
if (iop > iop_base && iop < iop_limit) (*iop++) = ',';
if (iop + plen > iop_limit)
plen = iop_limit - iop;
strncpy(iop, p, plen);
iop += plen;
}
p = q;
}
}
static void print_help(struct hsdis_app_data* app_data,
const char* msg, const char* arg) {
DECL_PRINTF_CALLBACK(app_data);
if (msg != NULL) {
(*printf_callback)(printf_stream, "hsdis: ");
(*printf_callback)(printf_stream, msg, arg);
(*printf_callback)(printf_stream, "\n");
}
(*printf_callback)(printf_stream, "hsdis output options:\n");
if (printf_callback == (printf_callback_t) &fprintf)
disassembler_usage((FILE*) printf_stream);
else
disassembler_usage(stderr); /* better than nothing */
(*printf_callback)(printf_stream, " mach=<arch> select disassembly mode\n");
#if defined(LIBARCH_i386) || defined(LIBARCH_amd64)
(*printf_callback)(printf_stream, " mach=i386 select 32-bit mode\n");
(*printf_callback)(printf_stream, " mach=x86-64 select 64-bit mode\n");
(*printf_callback)(printf_stream, " suffix always print instruction suffix\n");
#endif
(*printf_callback)(printf_stream, " help print this message\n");
}
/* low-level bfd and arch stuff that binutils doesn't do for us */
static const bfd_arch_info_type* find_arch_info(const char* arch_name) {
const bfd_arch_info_type* arch_info = bfd_scan_arch(arch_name);
if (arch_info == NULL) {
extern const bfd_arch_info_type bfd_default_arch_struct;
arch_info = &bfd_default_arch_struct;
}
return arch_info;
}
static const char* native_arch_name() {
const char* res = HOTSPOT_LIB_ARCH;
#ifdef LIBARCH_amd64
res = "i386:x86-64";
#endif
#ifdef LIBARCH_sparc
res = "sparc:v8plusb";
#endif
#ifdef LIBARCH_sparc
res = "sparc:v8plusb";
#endif
#ifdef LIBARCH_sparcv9
res = "sparc:v9b";
#endif
if (res == NULL)
res = "HOTSPOT_LIB_ARCH is not set in Makefile!";
return res;
}
static enum bfd_endian native_endian() {
int32_t endian_test = 'x';
if (*(const char*) &endian_test == 'x')
return BFD_ENDIAN_LITTLE;
else
return BFD_ENDIAN_BIG;
}
static bfd* get_native_bfd(const bfd_arch_info_type* arch_info,
bfd* empty_bfd, bfd_target* empty_xvec) {
memset(empty_bfd, 0, sizeof(*empty_bfd));
memset(empty_xvec, 0, sizeof(*empty_xvec));
empty_xvec->flavour = bfd_target_unknown_flavour;
empty_xvec->byteorder = native_endian();
empty_bfd->xvec = empty_xvec;
empty_bfd->arch_info = arch_info;
return empty_bfd;
}
static int read_zero_data_only(bfd_vma ignore_p,
bfd_byte* myaddr, unsigned int length,
struct disassemble_info *ignore_info) {
memset(myaddr, 0, length);
return 0;
}
static int print_to_dev_null(void* ignore_stream, const char* ignore_format, ...) {
return 0;
}
/* Prime the pump by running the selected disassembler on a null input.
This forces the machine-specific disassembler to divulge invariant
information like bytes_per_line.
*/
static void parse_fake_insn(disassembler_ftype dfn,
struct disassemble_info* dinfo) {
typedef int (*read_memory_ftype)
(bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
struct disassemble_info *info);
read_memory_ftype read_memory_func = dinfo->read_memory_func;
fprintf_ftype fprintf_func = dinfo->fprintf_func;
dinfo->read_memory_func = &read_zero_data_only;
dinfo->fprintf_func = &print_to_dev_null;
(*dfn)(0, dinfo);
// put it back:
dinfo->read_memory_func = read_memory_func;
dinfo->fprintf_func = fprintf_func;
}
static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo,
void *stream,
fprintf_ftype fprintf_func,
bfd* abfd,
char* disassembler_options) {
init_disassemble_info(dinfo, stream, fprintf_func);
dinfo->flavour = bfd_get_flavour(abfd);
dinfo->arch = bfd_get_arch(abfd);
dinfo->mach = bfd_get_mach(abfd);
dinfo->disassembler_options = disassembler_options;
dinfo->octets_per_byte = bfd_octets_per_byte (abfd);
dinfo->skip_zeroes = sizeof(void*) * 2;
dinfo->skip_zeroes_at_end = sizeof(void*)-1;
dinfo->disassembler_needs_relocs = FALSE;
if (bfd_big_endian(abfd))
dinfo->display_endian = dinfo->endian = BFD_ENDIAN_BIG;
else if (bfd_little_endian(abfd))
dinfo->display_endian = dinfo->endian = BFD_ENDIAN_LITTLE;
else
dinfo->endian = native_endian();
disassemble_init_for_target(dinfo);
}
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
/* decode_instructions -- dump a range of addresses as native instructions
This implements the protocol required by the HotSpot PrintAssembly option.
The starting and ending addresses are within the current process's address space.
The option string, if not empty, is interpreted by the disassembler implementation.
The printf callback is 'fprintf' or any other workalike.
It is called as (*printf_callback)(printf_stream, "some format...", some, format, args).
The event callback receives an event tag (a string) and an argument (a void*).
It is called as (*event_callback)(event_stream, "tag", arg).
Events:
<insn pc='%p'> begin an instruction, at a given location
</insn pc='%d'> end an instruction, at a given location
<addr value='%p'/> emit the symbolic value of an address
A tag format is one of three basic forms: "tag", "/tag", "tag/",
where tag is a simple identifier, signifying (as in XML) a element start,
element end, and standalone element. (To render as XML, add angle brackets.)
*/
extern
#ifdef DLL_EXPORT
DLL_EXPORT
#endif
void* decode_instructions(void* start, void* end,
void* (*event_callback)(void*, const char*, void*),
void* event_stream,
int (*printf_callback)(void*, const char*, ...),
void* printf_stream,
const char* options);
/* convenience typedefs */
typedef void* (*decode_instructions_event_callback_ftype) (void*, const char*, void*);
typedef int (*decode_instructions_printf_callback_ftype) (void*, const char*, ...);
typedef void* (*decode_instructions_ftype) (void* start, void* end,
decode_instructions_event_callback_ftype event_callback,
void* event_stream,
decode_instructions_printf_callback_ftype printf_callback,
void* printf_stream,
const char* options);
......@@ -947,6 +947,7 @@ void CodeComments::print_block_comment(outputStream* stream, intptr_t offset) {
if (_comments != NULL) {
CodeComment* c = _comments->find(offset);
while (c && c->offset() == offset) {
stream->bol();
stream->print(" ;; ");
stream->print_cr(c->comment());
c = c->next();
......
......@@ -707,7 +707,9 @@ nmethod::nmethod(
" entry points must be same for static methods and vice versa");
}
bool printnmethods = PrintNMethods || CompilerOracle::has_option_string(_method, "PrintNMethods");
bool printnmethods = PrintNMethods
|| CompilerOracle::should_print(_method)
|| CompilerOracle::has_option_string(_method, "PrintNMethods");
if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) {
print_nmethod(printnmethods);
}
......@@ -798,7 +800,6 @@ void nmethod::print_on(outputStream* st, const char* title) const {
}
#ifndef PRODUCT
void nmethod::print_nmethod(bool printmethod) {
ttyLocker ttyl; // keep the following output all in one block
if (xtty != NULL) {
......@@ -831,7 +832,6 @@ void nmethod::print_nmethod(bool printmethod) {
xtty->tail("print_nmethod");
}
}
#endif
void nmethod::set_version(int v) {
......@@ -1870,6 +1870,7 @@ void nmethod::check_store() {
}
}
#endif // PRODUCT
// Printing operations
......@@ -1948,6 +1949,14 @@ void nmethod::print() const {
oops_size());
}
void nmethod::print_code() {
HandleMark hm;
ResourceMark m;
Disassembler::decode(this);
}
#ifndef PRODUCT
void nmethod::print_scopes() {
// Find the first pc desc for all scopes in the code and print it.
......@@ -1979,13 +1988,6 @@ void nmethod::print_dependencies() {
}
void nmethod::print_code() {
HandleMark hm;
ResourceMark m;
Disassembler().decode(this);
}
void nmethod::print_relocations() {
ResourceMark m; // in case methods get printed via the debugger
tty->print_cr("relocations:");
......@@ -2021,6 +2023,7 @@ void nmethod::print_pcs() {
}
}
#endif // PRODUCT
const char* nmethod::reloc_string_for(u_char* begin, u_char* end) {
RelocIterator iter(this, begin, end);
......@@ -2055,7 +2058,6 @@ const char* nmethod::reloc_string_for(u_char* begin, u_char* end) {
return have_one ? "other" : NULL;
}
// Return a the last scope in (begin..end]
ScopeDesc* nmethod::scope_desc_in(address begin, address end) {
PcDesc* p = pc_desc_near(begin+1);
......@@ -2078,29 +2080,26 @@ void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin,
address pc = base + om->offset();
if (pc > begin) {
if (pc <= end) {
st->fill_to(column);
if (st == tty) {
st->print("; OopMap ");
om->print();
tty->cr();
} else {
st->print_cr("; OopMap #%d offset:%d", i, om->offset());
}
st->move_to(column);
st->print("; ");
om->print_on(st);
}
break;
}
}
}
// Print any debug info present at this pc.
ScopeDesc* sd = scope_desc_in(begin, end);
if (sd != NULL) {
st->fill_to(column);
st->move_to(column);
if (sd->bci() == SynchronizationEntryBCI) {
st->print(";*synchronization entry");
} else {
if (sd->method().is_null()) {
tty->print("method is NULL");
st->print("method is NULL");
} else if (sd->method()->is_native()) {
tty->print("method is native");
st->print("method is native");
} else {
address bcp = sd->method()->bcp_from(sd->bci());
Bytecodes::Code bc = Bytecodes::java_code_at(bcp);
......@@ -2137,13 +2136,13 @@ void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin,
}
}
}
st->cr();
// Print all scopes
for (;sd != NULL; sd = sd->sender()) {
st->fill_to(column);
st->move_to(column);
st->print("; -");
if (sd->method().is_null()) {
tty->print("method is NULL");
st->print("method is NULL");
} else {
sd->method()->print_short_name(st);
}
......@@ -2161,17 +2160,19 @@ void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin,
const char* str = reloc_string_for(begin, end);
if (str != NULL) {
if (sd != NULL) st->cr();
st->fill_to(column);
st->move_to(column);
st->print("; {%s}", str);
}
int cont_offset = ImplicitExceptionTable(this).at(begin - instructions_begin());
if (cont_offset != 0) {
st->fill_to(column);
st->move_to(column);
st->print("; implicit exception: dispatches to " INTPTR_FORMAT, instructions_begin() + cont_offset);
}
}
#ifndef PRODUCT
void nmethod::print_value_on(outputStream* st) const {
print_on(st, "nmethod");
}
......
......@@ -485,8 +485,8 @@ class nmethod : public CodeBlob {
void verify_interrupt_point(address interrupt_point);
// printing support
void print() const PRODUCT_RETURN;
void print_code() PRODUCT_RETURN;
void print() const;
void print_code();
void print_relocations() PRODUCT_RETURN;
void print_pcs() PRODUCT_RETURN;
void print_scopes() PRODUCT_RETURN;
......@@ -495,7 +495,7 @@ class nmethod : public CodeBlob {
void print_calls(outputStream* st) PRODUCT_RETURN;
void print_handler_table() PRODUCT_RETURN;
void print_nul_chk_table() PRODUCT_RETURN;
void print_nmethod(bool print_code) PRODUCT_RETURN;
void print_nmethod(bool print_code);
void print_on(outputStream* st, const char* title) const;
......@@ -505,7 +505,7 @@ class nmethod : public CodeBlob {
void log_state_change(int state) const;
// Prints a comment for one native instruction (reloc info, pc desc)
void print_code_comment_on(outputStream* st, int column, address begin, address end) PRODUCT_RETURN;
void print_code_comment_on(outputStream* st, int column, address begin, address end);
static void print_statistics() PRODUCT_RETURN;
// Compiler task identification. Note that all OSR methods
......
......@@ -36,7 +36,6 @@ const int VMRegImpl::register_count = ConcreteRegisterImpl::number_of_registers;
// Register names
const char *VMRegImpl::regName[ConcreteRegisterImpl::number_of_registers];
#ifndef PRODUCT
void VMRegImpl::print_on(outputStream* st) const {
if( is_reg() ) {
assert( VMRegImpl::regName[value()], "" );
......@@ -48,4 +47,3 @@ void VMRegImpl::print_on(outputStream* st) const {
st->print("BAD!");
}
}
#endif // PRODUCT
......@@ -96,7 +96,7 @@ public:
intptr_t value() const {return (intptr_t) this; }
void print_on(outputStream* st) const PRODUCT_RETURN;
void print_on(outputStream* st) const;
void print() const { print_on(tty); }
// bias a stack slot.
......@@ -156,22 +156,22 @@ public:
_first = ptr;
}
// Return true if single register, even if the pair is really just adjacent stack slots
bool is_single_reg() {
bool is_single_reg() const {
return (_first->is_valid()) && (_first->value() + 1 == _second->value());
}
// Return true if single stack based "register" where the slot alignment matches input alignment
bool is_adjacent_on_stack(int alignment) {
bool is_adjacent_on_stack(int alignment) const {
return (_first->is_stack() && (_first->value() + 1 == _second->value()) && ((_first->value() & (alignment-1)) == 0));
}
// Return true if single stack based "register" where the slot alignment matches input alignment
bool is_adjacent_aligned_on_stack(int alignment) {
bool is_adjacent_aligned_on_stack(int alignment) const {
return (_first->is_stack() && (_first->value() + 1 == _second->value()) && ((_first->value() & (alignment-1)) == 0));
}
// Return true if single register but adjacent stack slots do not count
bool is_single_phys_reg() {
bool is_single_phys_reg() const {
return (_first->is_reg() && (_first->value() + 1 == _second->value()));
}
......
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
# include "incls/_precompiled.incl"
# include "incls/_disassembler.cpp.incl"
void* Disassembler::_library = NULL;
bool Disassembler::_tried_to_load_library = false;
// This routine is in the shared library:
Disassembler::decode_func Disassembler::_decode_instructions = NULL;
static const char hsdis_library_name[] = "hsdis-"HOTSPOT_LIB_ARCH;
static const char decode_instructions_name[] = "decode_instructions";
#define COMMENT_COLUMN 40 LP64_ONLY(+8) /*could be an option*/
#define BYTES_COMMENT ";..." /* funky byte display comment */
bool Disassembler::load_library() {
if (_decode_instructions != NULL) {
// Already succeeded.
return true;
}
if (_tried_to_load_library) {
// Do not try twice.
// To force retry in debugger: assign _tried_to_load_library=0
return false;
}
// Try to load it.
char ebuf[1024];
char buf[JVM_MAXPATHLEN];
os::jvm_path(buf, sizeof(buf));
int jvm_offset = -1;
{
// Match "jvm[^/]*" in jvm_path.
const char* base = buf;
const char* p = strrchr(buf, '/');
p = strstr(p ? p : base, "jvm");
if (p != NULL) jvm_offset = p - base;
}
if (jvm_offset >= 0) {
// Find the disassembler next to libjvm.so.
strcpy(&buf[jvm_offset], hsdis_library_name);
strcat(&buf[jvm_offset], os::dll_file_extension());
_library = hpi::dll_load(buf, ebuf, sizeof ebuf);
}
if (_library == NULL) {
// Try a free-floating lookup.
strcpy(&buf[0], hsdis_library_name);
strcat(&buf[0], os::dll_file_extension());
_library = hpi::dll_load(buf, ebuf, sizeof ebuf);
}
if (_library != NULL) {
_decode_instructions = CAST_TO_FN_PTR(Disassembler::decode_func,
hpi::dll_lookup(_library, decode_instructions_name));
}
_tried_to_load_library = true;
if (_decode_instructions == NULL) {
tty->print_cr("Could not load %s; %s; %s", buf,
((_library != NULL)
? "entry point is missing"
: (WizardMode || PrintMiscellaneous)
? (const char*)ebuf
: "library not loadable"),
"PrintAssembly is disabled");
return false;
}
// Success.
tty->print_cr("Loaded disassembler from %s", buf);
return true;
}
class decode_env {
private:
nmethod* _nm;
CodeBlob* _code;
outputStream* _output;
address _start, _end;
char _option_buf[512];
char _print_raw;
bool _print_pc;
bool _print_bytes;
address _cur_insn;
int _total_ticks;
int _bytes_per_line; // arch-specific formatting option
static bool match(const char* event, const char* tag) {
size_t taglen = strlen(tag);
if (strncmp(event, tag, taglen) != 0)
return false;
char delim = event[taglen];
return delim == '\0' || delim == ' ' || delim == '/' || delim == '=';
}
void collect_options(const char* p) {
if (p == NULL || p[0] == '\0') return;
size_t opt_so_far = strlen(_option_buf);
if (opt_so_far + 1 + strlen(p) + 1 > sizeof(_option_buf)) return;
char* fillp = &_option_buf[opt_so_far];
if (opt_so_far > 0) *fillp++ = ',';
strcat(fillp, p);
// replace white space by commas:
char* q = fillp;
while ((q = strpbrk(q, " \t\n")) != NULL)
*q++ = ',';
// Note that multiple PrintAssemblyOptions flags accumulate with \n,
// which we want to be changed to a comma...
}
void print_insn_labels();
void print_insn_bytes(address pc0, address pc);
void print_address(address value);
public:
decode_env(CodeBlob* code, outputStream* output);
address decode_instructions(address start, address end);
void start_insn(address pc) {
_cur_insn = pc;
output()->bol();
print_insn_labels();
}
void end_insn(address pc) {
address pc0 = cur_insn();
outputStream* st = output();
if (_print_bytes && pc > pc0)
print_insn_bytes(pc0, pc);
if (_nm != NULL)
_nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc);
// Output pc bucket ticks if we have any
if (total_ticks() != 0) {
address bucket_pc = FlatProfiler::bucket_start_for(pc);
if (bucket_pc != NULL && bucket_pc > pc0 && bucket_pc <= pc) {
int bucket_count = FlatProfiler::bucket_count_for(pc0);
if (bucket_count != 0) {
st->bol();
st->print_cr("%3.1f%% [%d]", bucket_count*100.0/total_ticks(), bucket_count);
}
}
}
}
address handle_event(const char* event, address arg);
outputStream* output() { return _output; }
address cur_insn() { return _cur_insn; }
int total_ticks() { return _total_ticks; }
void set_total_ticks(int n) { _total_ticks = n; }
const char* options() { return _option_buf; }
};
decode_env::decode_env(CodeBlob* code, outputStream* output) {
memset(this, 0, sizeof(*this));
_output = output ? output : tty;
_code = code;
if (code != NULL && code->is_nmethod())
_nm = (nmethod*) code;
// by default, output pc but not bytes:
_print_pc = true;
_print_bytes = false;
_bytes_per_line = Disassembler::pd_instruction_alignment();
// parse the global option string:
collect_options(Disassembler::pd_cpu_opts());
collect_options(PrintAssemblyOptions);
if (strstr(options(), "hsdis-")) {
if (strstr(options(), "hsdis-print-raw"))
_print_raw = (strstr(options(), "xml") ? 2 : 1);
if (strstr(options(), "hsdis-print-pc"))
_print_pc = !_print_pc;
if (strstr(options(), "hsdis-print-bytes"))
_print_bytes = !_print_bytes;
}
if (strstr(options(), "help")) {
tty->print_cr("PrintAssemblyOptions help:");
tty->print_cr(" hsdis-print-raw test plugin by requesting raw output");
tty->print_cr(" hsdis-print-raw-xml test plugin by requesting raw xml");
tty->print_cr(" hsdis-print-pc turn off PC printing (on by default)");
tty->print_cr(" hsdis-print-bytes turn on instruction byte output");
tty->print_cr("combined options: %s", options());
}
}
address decode_env::handle_event(const char* event, address arg) {
if (match(event, "insn")) {
start_insn(arg);
} else if (match(event, "/insn")) {
end_insn(arg);
} else if (match(event, "addr")) {
if (arg != NULL) {
print_address(arg);
return arg;
}
} else if (match(event, "mach")) {
output()->print_cr("[Disassembling for mach='%s']", arg);
} else if (match(event, "format bytes-per-line")) {
_bytes_per_line = (int) (intptr_t) arg;
} else {
// ignore unrecognized markup
}
return NULL;
}
// called by the disassembler to print out jump targets and data addresses
void decode_env::print_address(address adr) {
outputStream* st = _output;
if (adr == NULL) {
st->print("NULL");
return;
}
int small_num = (int)(intptr_t)adr;
if ((intptr_t)adr == (intptr_t)small_num
&& -1 <= small_num && small_num <= 9) {
st->print("%d", small_num);
return;
}
if (Universe::is_fully_initialized()) {
if (StubRoutines::contains(adr)) {
StubCodeDesc* desc = StubCodeDesc::desc_for(adr);
if (desc == NULL)
desc = StubCodeDesc::desc_for(adr + frame::pc_return_offset);
if (desc != NULL) {
st->print("Stub::%s", desc->name());
if (desc->begin() != adr)
st->print("%+d 0x%p",adr - desc->begin(), adr);
else if (WizardMode) st->print(" " INTPTR_FORMAT, adr);
return;
}
st->print("Stub::<unknown> " INTPTR_FORMAT, adr);
return;
}
BarrierSet* bs = Universe::heap()->barrier_set();
if (bs->kind() == BarrierSet::CardTableModRef &&
adr == (address)((CardTableModRefBS*)(bs))->byte_map_base) {
st->print("word_map_base");
if (WizardMode) st->print(" " INTPTR_FORMAT, (intptr_t)adr);
return;
}
oop obj;
if (_nm != NULL
&& (obj = _nm->embeddedOop_at(cur_insn())) != NULL
&& (address) obj == adr) {
obj->print_value_on(st);
return;
}
}
// Fall through to a simple numeral.
st->print(INTPTR_FORMAT, (intptr_t)adr);
}
void decode_env::print_insn_labels() {
address p = cur_insn();
outputStream* st = output();
nmethod* nm = _nm;
if (nm != NULL) {
if (p == nm->entry_point()) st->print_cr("[Entry Point]");
if (p == nm->verified_entry_point()) st->print_cr("[Verified Entry Point]");
if (p == nm->exception_begin()) st->print_cr("[Exception Handler]");
if (p == nm->stub_begin()) st->print_cr("[Stub Code]");
if (p == nm->consts_begin()) st->print_cr("[Constants]");
}
CodeBlob* cb = _code;
if (cb != NULL) {
cb->print_block_comment(st, (intptr_t)(p - cb->instructions_begin()));
}
if (_print_pc) {
st->print(" " INTPTR_FORMAT ": ", (intptr_t) p);
}
}
void decode_env::print_insn_bytes(address pc, address pc_limit) {
outputStream* st = output();
size_t incr = 1;
size_t perline = _bytes_per_line;
if ((size_t) Disassembler::pd_instruction_alignment() >= sizeof(int)
&& !((uintptr_t)pc % sizeof(int))
&& !((uintptr_t)pc_limit % sizeof(int))) {
incr = sizeof(int);
if (perline % incr) perline += incr - (perline % incr);
}
while (pc < pc_limit) {
// tab to the desired column:
st->move_to(COMMENT_COLUMN);
address pc0 = pc;
address pc1 = pc + perline;
if (pc1 > pc_limit) pc1 = pc_limit;
for (; pc < pc1; pc += incr) {
if (pc == pc0)
st->print(BYTES_COMMENT);
else if ((uint)(pc - pc0) % sizeof(int) == 0)
st->print(" "); // put out a space on word boundaries
if (incr == sizeof(int))
st->print("%08lx", *(int*)pc);
else st->print("%02x", (*pc)&0xFF);
}
st->cr();
}
}
static void* event_to_env(void* env_pv, const char* event, void* arg) {
decode_env* env = (decode_env*) env_pv;
return env->handle_event(event, (address) arg);
}
static int printf_to_env(void* env_pv, const char* format, ...) {
decode_env* env = (decode_env*) env_pv;
outputStream* st = env->output();
size_t flen = strlen(format);
const char* raw = NULL;
if (flen == 0) return 0;
if (flen == 1 && format[0] == '\n') { st->bol(); return 1; }
if (flen < 2 ||
strchr(format, '%') == NULL) {
raw = format;
} else if (format[0] == '%' && format[1] == '%' &&
strchr(format+2, '%') == NULL) {
// happens a lot on machines with names like %foo
flen--;
raw = format+1;
}
if (raw != NULL) {
st->print_raw(raw, (int) flen);
return (int) flen;
}
va_list ap;
va_start(ap, format);
julong cnt0 = st->count();
st->vprint(format, ap);
julong cnt1 = st->count();
va_end(ap);
return (int)(cnt1 - cnt0);
}
address decode_env::decode_instructions(address start, address end) {
_start = start; _end = end;
assert((((intptr_t)start | (intptr_t)end) % Disassembler::pd_instruction_alignment() == 0), "misaligned insn addr");
const int show_bytes = false; // for disassembler debugging
//_version = Disassembler::pd_cpu_version();
if (!Disassembler::can_decode()) {
return NULL;
}
// decode a series of instructions and return the end of the last instruction
if (_print_raw) {
// Print whatever the library wants to print, w/o fancy callbacks.
// This is mainly for debugging the library itself.
FILE* out = stdout;
FILE* xmlout = (_print_raw > 1 ? out : NULL);
return (address)
(*Disassembler::_decode_instructions)(start, end,
NULL, (void*) xmlout,
NULL, (void*) out,
options());
}
return (address)
(*Disassembler::_decode_instructions)(start, end,
&event_to_env, (void*) this,
&printf_to_env, (void*) this,
options());
}
void Disassembler::decode(CodeBlob* cb, outputStream* st) {
if (!load_library()) return;
decode_env env(cb, st);
env.output()->print_cr("Decoding CodeBlob " INTPTR_FORMAT, cb);
env.decode_instructions(cb->instructions_begin(), cb->instructions_end());
}
void Disassembler::decode(address start, address end, outputStream* st) {
if (!load_library()) return;
decode_env env(CodeCache::find_blob_unsafe(start), st);
env.decode_instructions(start, end);
}
void Disassembler::decode(nmethod* nm, outputStream* st) {
if (!load_library()) return;
decode_env env(nm, st);
env.output()->print_cr("Decoding compiled method " INTPTR_FORMAT ":", nm);
env.output()->print_cr("Code:");
unsigned char* p = nm->instructions_begin();
unsigned char* end = nm->instructions_end();
// If there has been profiling, print the buckets.
if (FlatProfiler::bucket_start_for(p) != NULL) {
unsigned char* p1 = p;
int total_bucket_count = 0;
while (p1 < end) {
unsigned char* p0 = p1;
p1 += pd_instruction_alignment();
address bucket_pc = FlatProfiler::bucket_start_for(p1);
if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p1)
total_bucket_count += FlatProfiler::bucket_count_for(p0);
}
env.set_total_ticks(total_bucket_count);
}
env.decode_instructions(p, end);
}
/*
* Copyright 1997-2002 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2008 Sun Microsystems, Inc. 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
......@@ -22,14 +22,38 @@
*
*/
// Call-back interface for external disassembler
class DisassemblerEnv {
class decode_env;
// The disassembler prints out assembly code annotated
// with Java specific information.
class Disassembler {
friend class decode_env;
private:
// this is the type of the dll entry point:
typedef void* (*decode_func)(void* start, void* end,
void* (*event_callback)(void*, const char*, void*),
void* event_stream,
int (*printf_callback)(void*, const char*, ...),
void* printf_stream,
const char* options);
// points to the library.
static void* _library;
// bailout
static bool _tried_to_load_library;
// points to the decode function.
static decode_func _decode_instructions;
// tries to load library and return whether it succedded.
static bool load_library();
// Machine dependent stuff
#include "incls/_disassembler_pd.hpp.incl"
public:
// printing
virtual void print_label(intptr_t value) = 0;
virtual void print_raw(char* str) = 0;
virtual void print(char* format, ...) = 0;
// helpers
virtual char* string_for_offset(intptr_t value) = 0;
virtual char* string_for_constant(unsigned char* pc, intptr_t value, int is_decimal) = 0;
static bool can_decode() {
return (_decode_instructions != NULL) || load_library();
}
static void decode(CodeBlob *cb, outputStream* st = NULL);
static void decode(nmethod* nm, outputStream* st = NULL);
static void decode(address begin, address end, outputStream* st = NULL);
};
......@@ -505,8 +505,13 @@ bool OopMap::has_derived_pointer() const {
#endif // COMPILER2
}
#endif //PRODUCT
static void print_register_type(OopMapValue::oop_types x, VMReg optional, outputStream* st) {
// Printing code is present in product build for -XX:+PrintAssembly.
static
void print_register_type(OopMapValue::oop_types x, VMReg optional,
outputStream* st) {
switch( x ) {
case OopMapValue::oop_value:
st->print("Oop");
......@@ -544,10 +549,12 @@ void OopMapValue::print_on(outputStream* st) const {
void OopMap::print_on(outputStream* st) const {
OopMapValue omv;
st->print("OopMap{");
for(OopMapStream oms((OopMap*)this); !oms.is_done(); oms.next()) {
omv = oms.current();
omv.print_on(st);
}
st->print("off=%d}", (int) offset());
}
......@@ -558,12 +565,12 @@ void OopMapSet::print_on(outputStream* st) const {
for( i = 0; i < len; i++) {
OopMap* m = at(i);
st->print_cr("OopMap #%d offset:%p",i,m->offset());
st->print_cr("#%d ",i);
m->print_on(st);
st->print_cr("\n");
st->cr();
}
}
#endif // !PRODUCT
//------------------------------DerivedPointerTable---------------------------
......
......@@ -129,7 +129,7 @@ public:
return reg()->reg2stack();
}
void print_on(outputStream* st) const PRODUCT_RETURN;
void print_on(outputStream* st) const;
void print() const { print_on(tty); }
};
......@@ -193,7 +193,7 @@ class OopMap: public ResourceObj {
}
// Printing
void print_on(outputStream* st) const PRODUCT_RETURN;
void print_on(outputStream* st) const;
void print() const { print_on(tty); }
};
......@@ -248,7 +248,7 @@ class OopMapSet : public ResourceObj {
OopClosure* value_fn, OopClosure* dead_fn);
// Printing
void print_on(outputStream* st) const PRODUCT_RETURN;
void print_on(outputStream* st) const;
void print() const { print_on(tty); }
};
......
......@@ -323,7 +323,7 @@ c1_Runtime1.cpp collectedHeap.hpp
c1_Runtime1.cpp compilationPolicy.hpp
c1_Runtime1.cpp compiledIC.hpp
c1_Runtime1.cpp copy.hpp
c1_Runtime1.cpp disassembler_<arch>.hpp
c1_Runtime1.cpp disassembler.hpp
c1_Runtime1.cpp events.hpp
c1_Runtime1.cpp interfaceSupport.hpp
c1_Runtime1.cpp interpreter.hpp
......
......@@ -244,7 +244,7 @@ assembler.hpp vm_version_<arch_model>.hpp
assembler.inline.hpp assembler.hpp
assembler.inline.hpp codeBuffer.hpp
assembler.inline.hpp disassembler_<arch>.hpp
assembler.inline.hpp disassembler.hpp
assembler.inline.hpp threadLocalStorage.hpp
assembler_<arch_model>.cpp assembler_<arch_model>.inline.hpp
......@@ -946,7 +946,7 @@ codeBlob.cpp allocation.inline.hpp
codeBlob.cpp bytecode.hpp
codeBlob.cpp codeBlob.hpp
codeBlob.cpp codeCache.hpp
codeBlob.cpp disassembler_<arch>.hpp
codeBlob.cpp disassembler.hpp
codeBlob.cpp forte.hpp
codeBlob.cpp handles.inline.hpp
codeBlob.cpp heap.hpp
......@@ -968,7 +968,7 @@ codeBlob.hpp oopMap.hpp
codeBuffer.cpp codeBuffer.hpp
codeBuffer.cpp copy.hpp
codeBuffer.cpp disassembler_<arch>.hpp
codeBuffer.cpp disassembler.hpp
codeBuffer.hpp assembler.hpp
codeBuffer.hpp oopRecorder.hpp
......@@ -1323,7 +1323,7 @@ debug.cpp codeCache.hpp
debug.cpp collectedHeap.hpp
debug.cpp compileBroker.hpp
debug.cpp defaultStream.hpp
debug.cpp disassembler_<arch>.hpp
debug.cpp disassembler.hpp
debug.cpp events.hpp
debug.cpp frame.hpp
debug.cpp heapDumper.hpp
......@@ -1442,7 +1442,7 @@ deoptimization.hpp allocation.hpp
deoptimization.hpp frame.inline.hpp
depChecker_<arch>.cpp depChecker_<arch>.hpp
depChecker_<arch>.cpp disassembler_<arch>.hpp
depChecker_<arch>.cpp disassembler.hpp
depChecker_<arch>.cpp hpi.hpp
dependencies.cpp ciArrayKlass.hpp
......@@ -1472,21 +1472,21 @@ dictionary.hpp instanceKlass.hpp
dictionary.hpp oop.hpp
dictionary.hpp systemDictionary.hpp
disassemblerEnv.hpp globals.hpp
disassembler_<arch>.hpp generate_platform_dependent_include
disassembler_<arch>.cpp cardTableModRefBS.hpp
disassembler_<arch>.cpp codeCache.hpp
disassembler_<arch>.cpp collectedHeap.hpp
disassembler_<arch>.cpp depChecker_<arch>.hpp
disassembler_<arch>.cpp disassembler_<arch>.hpp
disassembler_<arch>.cpp fprofiler.hpp
disassembler_<arch>.cpp handles.inline.hpp
disassembler_<arch>.cpp hpi.hpp
disassembler_<arch>.cpp stubCodeGenerator.hpp
disassembler_<arch>.cpp stubRoutines.hpp
disassembler.cpp cardTableModRefBS.hpp
disassembler.cpp codeCache.hpp
disassembler.cpp collectedHeap.hpp
disassembler.cpp depChecker_<arch>.hpp
disassembler.cpp disassembler.hpp
disassembler.cpp fprofiler.hpp
disassembler.cpp handles.inline.hpp
disassembler.cpp hpi.hpp
disassembler.cpp stubCodeGenerator.hpp
disassembler.cpp stubRoutines.hpp
disassembler_<arch>.hpp disassemblerEnv.hpp
disassembler_<arch>.hpp os_<os_family>.inline.hpp
disassembler.hpp globals.hpp
disassembler.hpp os_<os_family>.inline.hpp
dtraceAttacher.cpp codeCache.hpp
dtraceAttacher.cpp deoptimization.hpp
......@@ -2909,7 +2909,7 @@ nmethod.cpp codeCache.hpp
nmethod.cpp compileLog.hpp
nmethod.cpp compiledIC.hpp
nmethod.cpp compilerOracle.hpp
nmethod.cpp disassembler_<arch>.hpp
nmethod.cpp disassembler.hpp
nmethod.cpp dtrace.hpp
nmethod.cpp events.hpp
nmethod.cpp jvmtiRedefineClassesTrace.hpp
......@@ -3763,7 +3763,7 @@ statSampler.hpp perfData.hpp
statSampler.hpp task.hpp
stubCodeGenerator.cpp assembler_<arch_model>.inline.hpp
stubCodeGenerator.cpp disassembler_<arch>.hpp
stubCodeGenerator.cpp disassembler.hpp
stubCodeGenerator.cpp forte.hpp
stubCodeGenerator.cpp oop.inline.hpp
stubCodeGenerator.cpp stubCodeGenerator.hpp
......@@ -4530,7 +4530,7 @@ vmreg_<arch>.cpp vmreg.hpp
vmreg_<arch>.hpp generate_platform_dependent_include
vtableStubs.cpp allocation.inline.hpp
vtableStubs.cpp disassembler_<arch>.hpp
vtableStubs.cpp disassembler.hpp
vtableStubs.cpp forte.hpp
vtableStubs.cpp handles.inline.hpp
vtableStubs.cpp instanceKlass.hpp
......
......@@ -456,7 +456,15 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
}
TraceTime t1("Total compilation time", &_t_totalCompilation, TimeCompiler, TimeCompiler2);
TraceTime t2(NULL, &_t_methodCompilation, TimeCompiler, false);
set_print_assembly(PrintOptoAssembly || _method->should_print_assembly());
bool print_opto_assembly = PrintOptoAssembly || _method->has_option("PrintOptoAssembly");
if (!print_opto_assembly) {
bool print_assembly = (PrintAssembly || _method->should_print_assembly());
if (print_assembly && !Disassembler::can_decode()) {
tty->print_cr("PrintAssembly request changed to PrintOptoAssembly");
print_opto_assembly = true;
}
}
set_print_assembly(print_opto_assembly);
#endif
if (ProfileTraps) {
......
......@@ -668,16 +668,19 @@ class CommandLineFlags {
notproduct(bool, PrintCompilation2, false, \
"Print additional statistics per compilation") \
\
notproduct(bool, PrintAdapterHandlers, false, \
diagnostic(bool, PrintAdapterHandlers, false, \
"Print code generated for i2c/c2i adapters") \
\
develop(bool, PrintAssembly, false, \
"Print assembly code") \
diagnostic(bool, PrintAssembly, false, \
"Print assembly code (using external disassembler.so)") \
\
develop(bool, PrintNMethods, false, \
diagnostic(ccstr, PrintAssemblyOptions, false, \
"Options string passed to disassembler.so") \
\
diagnostic(bool, PrintNMethods, false, \
"Print assembly code for nmethods when generated") \
\
develop(bool, PrintNativeNMethods, false, \
diagnostic(bool, PrintNativeNMethods, false, \
"Print assembly code for native nmethods when generated") \
\
develop(bool, PrintDebugInfo, false, \
......@@ -702,7 +705,7 @@ class CommandLineFlags {
develop(bool, PrintCodeCache2, false, \
"Print detailed info on the compiled_code cache when exiting") \
\
develop(bool, PrintStubCode, false, \
diagnostic(bool, PrintStubCode, false, \
"Print generated stub code") \
\
product(bool, StackTraceInThrowable, true, \
......@@ -2250,7 +2253,7 @@ class CommandLineFlags {
product_pd(bool, RewriteFrequentPairs, \
"Rewrite frequently used bytecode pairs into a single bytecode") \
\
product(bool, PrintInterpreter, false, \
diagnostic(bool, PrintInterpreter, false, \
"Prints the generated interpreter code") \
\
product(bool, UseInterpreter, true, \
......@@ -2300,7 +2303,7 @@ class CommandLineFlags {
develop(bool, PrintBytecodePairHistogram, false, \
"Print histogram of the executed bytecode pairs") \
\
develop(bool, PrintSignatureHandlers, false, \
diagnostic(bool, PrintSignatureHandlers, false, \
"Print code generated for native method signature handlers") \
\
develop(bool, VerifyOops, false, \
......
......@@ -69,7 +69,6 @@ StubCodeGenerator::StubCodeGenerator(CodeBuffer* code) {
_first_stub = _last_stub = NULL;
}
#ifndef PRODUCT
extern "C" {
static int compare_cdesc(const void* void_a, const void* void_b) {
int ai = (*((StubCodeDesc**) void_a))->index();
......@@ -77,10 +76,8 @@ extern "C" {
return ai - bi;
}
}
#endif
StubCodeGenerator::~StubCodeGenerator() {
#ifndef PRODUCT
if (PrintStubCode) {
CodeBuffer* cbuf = _masm->code();
CodeBlob* blob = CodeCache::find_blob_unsafe(cbuf->insts()->start());
......@@ -105,7 +102,6 @@ StubCodeGenerator::~StubCodeGenerator() {
tty->cr();
}
}
#endif //PRODUCT
}
......
......@@ -52,8 +52,9 @@ void outputStream::update_position(const char* s, size_t len) {
_precount += _position + 1;
_position = 0;
} else if (ch == '\t') {
_position += 8;
_precount -= 7; // invariant: _precount + _position == total count
int tw = 8 - (_position & 7);
_position += tw;
_precount -= tw-1; // invariant: _precount + _position == total count
} else {
_position += 1;
}
......@@ -133,7 +134,17 @@ void outputStream::vprint_cr(const char* format, va_list argptr) {
}
void outputStream::fill_to(int col) {
while (position() < col) sp();
int need_fill = col - position();
sp(need_fill);
}
void outputStream::move_to(int col, int slop, int min_space) {
if (position() >= col + slop)
cr();
int need_fill = col - position();
if (need_fill < min_space)
need_fill = min_space;
sp(need_fill);
}
void outputStream::put(char ch) {
......@@ -142,8 +153,23 @@ void outputStream::put(char ch) {
write(buf, 1);
}
void outputStream::sp() {
this->write(" ", 1);
#define SP_USE_TABS false
void outputStream::sp(int count) {
if (count < 0) return;
if (SP_USE_TABS && count >= 8) {
int target = position() + count;
while (count >= 8) {
this->write("\t", 1);
count -= 8;
}
count = target - position();
}
while (count > 0) {
int nw = (count > 8) ? 8 : count;
this->write(" ", nw);
count -= nw;
}
}
void outputStream::cr() {
......
......@@ -59,6 +59,7 @@ class outputStream : public ResourceObj {
int indentation() const { return _indentation; }
void set_indentation(int i) { _indentation = i; }
void fill_to(int col);
void move_to(int col, int slop = 6, int min_space = 2);
// sizing
int width() const { return _width; }
......@@ -78,7 +79,7 @@ class outputStream : public ResourceObj {
void print_raw_cr(const char* str) { write(str, strlen(str)); cr(); }
void print_raw_cr(const char* str, int len){ write(str, len); cr(); }
void put(char ch);
void sp();
void sp(int count = 1);
void cr();
void bol() { if (_position > 0) cr(); }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册