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