Question
chenjie
chenj at lemote.com
Thu Aug 9 19:50:14 PDT 2007
Thank Volker for the message, actually, It is quit easy for MIPS to
disassemble, because its instruction are fixed length, We have
implemented a simple disassembler for JVM last year.
Volker Simonis дµÀ:
> Hi Guys,
>
> time to go back to the original topic:
>
> here comes a 'disassembler_i486.cpp' that uses a vanilla
> 'libopcodes.so' how it comes with every binutils distribution. It can
> be used as a simple replacement for the current
> 'disassembler_i486.cpp'. The only requirements during compile time is
> 'dis-asm.h' which is also provided by the binutils package. Usually
> this should be availabel on Linux and should be no problem on Windows
> as well if you use Cygwin anyway (I tried only on Linux).
>
> After compiling the HotSpot with the new version of
> 'disassembler_i486.cpp' you should now be able to use the various
> print options like for example -XX:+PrintCompilation
> -XX:+PrintAssembly, -XX:+PrintInterpreter and get a nice assembly
> output of wht's going on under the hood.
>
> @chenjie: this should also work on MIPS as binutils support MIPS.
> Could you check? Maybe it can be helpfull for your porting project.
>
> Implementation details
> --------------------------
> I specially kept the diff to the original file small, so you can
> easily see what the crucial changes are. If this should get into the
> official release, we can of course get rid of a few things like for
> example the class 'i486_env' and 'Disassembler::decode_instruction'
> that arn't needed anymore.
>
> For other architectures, all that has to be done, is adapt the
> following lines in 'init_disassemble_info()':
>
> // Platform dependent stuff (i486)
> di.bytes_per_line = 0;
> di.endian = (bfd_endian) 1;
> di.mach = bfd_mach_i386_i8086;
> di.disassembler_options = (char *) "i386,suffix";
>
> and choose the right name for the disassembler function in
> 'Disassembler::load_library()':
>
> hpi::dll_lookup(_library, "print_insn_i386");
>
> The specific names for other architectures can be found in 'dis-asm.h'.
>
> Pitfalls
> --------
> On my Suse Linux 10 I had a broken 'libopcodes.so' ("nm
> /usr/lib/libopcodes.so" returned no symbols. But building a new
> version of binutils is quite tricky too, because you HAVE to give
> ./configure the "--enable-64-bit-bfd" option (even on 32bit Linux),
> otherwise the resulting 'libopcodes.so' wont work! Heres my configure
> line for building binutils 2.17:
>
> ./configure --enable-shared --enable-64-bit-bfd
>
> Afterwards, just copy opcodes/.libs/libopcodes-2.17.so to /usr/lib and
> let /usr/lib/libopcodes.so link to it. That's it.
>
> Regards,
> Volker
>
> On 8/8/07, Peter B. Kessler <Peter.Kessler at sun.com> wrote:
>
>> Christian Thalinger wrote:
>>
>>
>>> On Wed, 2007-08-08 at 12:45 -0700, Peter B. Kessler wrote:
>>>
>>> Hi Peter!
>>>
>>>
>>>> Could we move this thread from hotspot-compiler-dev at openjdk.dev.java.net
>>>> to hotspot-compiler-dev at openjdk.java.net? The first list just forwards
>>>> to the second list, but since you all are subscribed to the second list
>>>> but not the first list, I have to approve all your postings to the first
>>>> list. That means my lack of attention is just slowing you all down.
>>>> I'm in the way to serve as a spam filter. (Part of garbage collection? :-)
>>>>
>>> Hehe :-)
>>>
>>>
>>>> I assume most of you are just hitting "Reply-All" and so aren't even
>>>> aware of the difference between openjdk.dev.java.net and openjdk.java.net.
>>>> But you might also want to check your address books to see that new posts
>>>> to hotspot-compiler-dev will go to openjdk.java.net.
>>>>
>>> OK. This list?
>>>
>>> - twisti
>>>
>> Yes. Thanks. Now, what was the original topic? :-)
>>
>> ... peter
>>
>>
>> ------------------------------------------------------------------------
>>
>> #ifdef USE_PRAGMA_IDENT_SRC
>> #pragma ident "@(#)disassembler_i486.cpp 1.47 07/05/05 17:04:14 JVM"
>> #endif
>> /*
>> * 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_i486.cpp.incl"
>>
>> #ifndef PRODUCT
>>
>> #include <dis-asm.h>
>>
>> void* Disassembler::_library = NULL;
>> Disassembler::decode_func Disassembler::_decode_instruction = NULL;
>> disassembler_ftype _decode_instruction = NULL;
>>
>> // Callback function that will be called by libopcodes to print
>> // disassembled code ('fprintf_func' member of 'disassemble_info').
>> extern "C" int fprint_func(void *stream, const char* format, ...) {
>> outputStream* st = reinterpret_cast<outputStream*>(stream);
>> va_list ap;
>> va_start(ap, format);
>> st->vprint(format, ap);
>> va_end(ap);
>> }
>>
>> // Callback function that will be called by libopcodes to read the
>> // bytes to disassemble ('read_memory_func' member of 'disassemble_info').
>> extern "C" int read_memory_func(bfd_vma memaddr, bfd_byte *myaddr,
>> unsigned int length, disassemble_info *info) {
>> char* from = reinterpret_cast<char*>(memaddr);
>> char* to = (char*)myaddr;
>>
>> while (length-- != 0) {
>> *to++ = *from++;
>> }
>> return (0);
>> }
>>
>> // Callback function that will be called by libopcodes to print
>> // addresses ('print_address_func' member of 'disassemble_info').
>> extern "C" void print_address_func( bfd_vma addr, disassemble_info *info) {
>> outputStream* st = reinterpret_cast<outputStream*>(info->stream);
>> st->print("0x%x", addr);
>> }
>>
>> // Initialize a 'disassemble_info' structure for further calls to
>> // the libopcodes decode function.
>> static void init_disassemble_info(disassemble_info &di, const outputStream *st) {
>> // Platform dependent stuff (i486)
>> di.bytes_per_line = 0;
>> di.endian = (bfd_endian) 1;
>> di.mach = bfd_mach_i386_i8086;
>> di.disassembler_options = (char *) "i386,suffix";
>> // Shared stuff that will be equal for all platforms
>> di.stream = (void*)st;
>> di.fprintf_func = fprint_func;
>> di.read_memory_func = read_memory_func;
>> di.print_address_func = print_address_func;
>> }
>>
>> bool Disassembler::load_library() {
>> if (_library == NULL) {
>> char buf[1024];
>> char ebuf[1024];
>> sprintf(buf, "libopcodes%s", os::dll_file_extension());
>> _library = hpi::dll_load(buf, ebuf, sizeof ebuf);
>> if (_library != NULL) {
>> tty->print_cr("Loaded disassembler");
>> ::_decode_instruction = (disassembler_ftype)
>> hpi::dll_lookup(_library, "print_insn_i386");
>> }
>> }
>> return (_library != NULL) && (::_decode_instruction != NULL);
>> }
>>
>> class i486_env : public DisassemblerEnv {
>> private:
>> nmethod* code;
>> outputStream* output;
>> public:
>> i486_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 i486_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 i486_env::print(char* format, ...) {
>> va_list ap;
>> va_start(ap, format);
>> output->vprint(format, ap);
>> va_end(ap);
>> }
>>
>> char* i486_env::string_for_offset(intptr_t value) {
>> stringStream st;
>> if (!Universe::is_fully_initialized()) {
>> st.print("%d", 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("%d", value);
>> }
>> return st.as_string();
>> }
>>
>> char* i486_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("%d", value);
>> } else {
>> st.print("0x%lx", 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;
>> }
>>
>> disassemble_info di;
>> init_disassemble_info(di, 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(reinterpret_cast<bfd_vma>(p), &di);
>> 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;
>> }
>> disassemble_info di;
>> init_disassemble_info(di, 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(reinterpret_cast<bfd_vma>(p), &di);
>> 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
>>
>>
More information about the hotspot-compiler-dev
mailing list