ARM: Rewrite disassembler to use hsdis

Andrew Haley aph at redhat.com
Fri Jan 20 07:50:45 PST 2012


This patch rewrites the ARM disassembler to use HSDIS rather than call
binutils directly.  This removes the build dependency on
binutils-devel.  We have to do this because binutils is GPLv3+ and
HotSpot is GPLv2 only.  I had to patch HSDIS itself to make it work on
ARM; I'll send that patch upstream as well as to IcedTea.

I also took the opportunity to use the global PrintAssembly setting,
but the old T2EE_PRINT_DISASS environment variable stil works if you
want to use that.

This is for trunk and branch.

Andrew.



diff -r 8c63d311e066 Makefile.am
--- a/Makefile.am	Thu Jan 19 07:16:03 2012 -0500
+++ b/Makefile.am	Fri Jan 20 10:43:58 2012 -0500
@@ -399,6 +399,7 @@
 	patches/openjdk/6296893-BMP_Writer_handles_TopDown_prop_incorrectly.patch \
 	patches/openjdk/7103224-glibc_name_collision.patch \
 	patches/arm-debug.patch \
+	patches/arm-hsdis.patch	\
 	patches/openjdk/7103610-_NET_WM_PID_and_WM_CLIENT_MACHINE_are_not_set.patch \
 	patches/openjdk/7102369-7094468-rmiregistry.patch \
 	patches/openjdk/6851973-kerberos.patch \
diff -r 8c63d311e066 arm_port/hotspot/src/cpu/zero/vm/thumb2.cpp
--- a/arm_port/hotspot/src/cpu/zero/vm/thumb2.cpp	Thu Jan 19 07:16:03 2012 -0500
+++ b/arm_port/hotspot/src/cpu/zero/vm/thumb2.cpp	Fri Jan 20 10:43:58 2012 -0500
@@ -38,10 +38,6 @@
 static char *t2ee_print_statistics;
 #endif

-#ifdef T2EE_PRINT_DISASS
-static char *t2ee_print_disass;
-#endif
-
 #ifdef T2EE_PRINT_REGUSAGE
 static char *t2ee_print_regusage;
 #endif
@@ -56,11 +52,6 @@
 #include "precompiled.hpp"
 #include "interpreter/bytecodes.hpp"

-#ifdef T2EE_PRINT_DISASS
-#include "dis-asm.h"
-#include "bfd.h"
-#endif
-
 #define opc_nop			0x00
 #define opc_aconst_null		0x01
 #define opc_iconst_m1		0x02
@@ -725,41 +716,44 @@

 #ifdef T2EE_PRINT_DISASS

-class Opcodes {
+class Hsdis {
 public:
-  typeof (::print_insn_little_arm) *print_insn_little_arm;
-  typeof (::init_disassemble_info) *init_disassemble_info;
-  typeof (::disassemble_init_for_target) *disassemble_init_for_target;
-
-  // Load libopcodes.so lazily.
-  Opcodes()
+
+  typedef void* (*decode_instructions_event_callback_ftype)  (void*, const char*, void*);
+
+  typedef void* (*decode_instructions_ftype)
+    (void* start, void* end,
+     decode_instructions_event_callback_ftype event_callback,
+     void* event_stream,
+     void* printf_callback,
+     void* printf_stream,
+     const char* options);
+
+  decode_instructions_ftype decode_instructions;
+
+  void *lib;
+
+  // Load hsdis-arm.so lazily.
+  Hsdis()
   {
-    void *lib;
-    if (t2ee_print_disass) {
-      if (lib = dlopen("libopcodes.so", RTLD_NOW)) {
-	print_insn_little_arm
-	  = (typeof print_insn_little_arm)dlsym(lib, "print_insn_little_arm");
-	init_disassemble_info
-	  = (typeof init_disassemble_info)dlsym(lib, "init_disassemble_info");
-	disassemble_init_for_target
-	  = (typeof disassemble_init_for_target)dlsym(lib, "disassemble_init_for_target");
+    if (PrintAssembly) {
+      if (lib = dlopen("hsdis-arm.so", RTLD_NOW)) {
+	decode_instructions
+	  = (typeof decode_instructions)dlsym(lib, "decode_instructions");
       }

-      if (! (print_insn_little_arm
-	     && init_disassemble_info
-	     && disassemble_init_for_target))
-	{
-	  fprintf (stderr, "The environment variable T2EE_PRINT_DISASS is set, but\n"
-		   "libopcodes.so has not been found or is invalid.  If you want to\n"
-		   "see a disassembly, please ensure that a valid copy of\n"
-		   "libopcodes.so is present somewhere in your library load path.\n");
-	  abort();
-	}
+      if (! (decode_instructions)) {
+	fprintf (stderr, "PrintAssembly (or T2EE_PRINT_DISASS) is set, but\n"
+		 "hsdis-arm.so has not been found or is invalid.  If you want to\n"
+		 "see a disassembly, please ensure that a valid copy of\n"
+		 "hsdis-arm.so is present somewhere in your library load path.\n");
+	abort();
+      }
     }
   }
 };

-static Opcodes opcodes;
+static void *print_address(void *stream, const char *tag, void *data);

 void Thumb2_disass(Thumb2_Info *jinfo)
 {
@@ -773,10 +767,11 @@
   int start_b, end_b;
   unsigned nodisass;

-  struct disassemble_info info;
   unsigned short *codebuf = jinfo->codebuf->codebuf;
   unsigned idx, compiled_len;

+  static Hsdis hsdis;
+
 #if 0
   printf("Local Variable Usage\n");
   printf("====================\n");
@@ -794,16 +789,6 @@
   fflush(stdout);
   fflush(stderr);

-  opcodes.init_disassemble_info(&info, stdout, (fprintf_ftype)fprintf);
-  info.arch = bfd_arch_arm;
-  opcodes.disassemble_init_for_target(&info);
-  info.endian = BFD_ENDIAN_LITTLE;
-  info.endian_code = BFD_ENDIAN_LITTLE;
-  info.buffer = (bfd_byte *)codebuf;
-  info.buffer_vma = (bfd_vma)codebuf;
-  info.buffer_length = jinfo->codebuf->idx * sizeof(short);
-  info.disassembler_options = (char *)"force-thumb";
-
   compiled_len = jinfo->codebuf->idx * 2;
   for (idx = 0; idx < compiled_len; ) {
     nodisass = 0;
@@ -867,13 +852,14 @@
 	      low++;
 	    }
 	    bci += len;
-	    for (i = 0; i < 4; i++) {
+	    {
 	      printf("0x%08x:\t", (int)codebuf+idx);
 	      {
-		int len = opcodes.print_insn_little_arm((bfd_vma)codebuf+idx, &info);
-		if (len == -1) len = 2;
-		idx += len;
-		putchar('\n');
+		unsigned short *p = codebuf + idx/2;
+		hsdis.decode_instructions((char*)p, (char *)p + 14,
+					  print_address, NULL, NULL, stdout,
+					  "force-thumb");
+		idx += 14;
 	      }
 	    }
 	    for (i = 0; i < n; i++) {
@@ -929,7 +915,6 @@
       }
     }
     if (!nodisass) {
-      printf("0x%08x:\t", (int)codebuf+idx);
       {
 	int len;
 	unsigned s1, s2;
@@ -945,16 +930,26 @@
 	    len = 4;
 	  }
 	} else {
-	  len = opcodes.print_insn_little_arm((bfd_vma)codebuf+idx, &info);
-	  if (len == -1) len = 2;
-	  idx += len;
+	  char *p = (char*)codebuf + idx;
+	  len = 2;
+	  while (len + idx < compiled_len
+		 && start_bci[(len + idx)/2] == -1)
+	    len += 2;
+	  hsdis.decode_instructions((char*)p, (char*)p + len,
+				      print_address, NULL, NULL, stdout,
+				      "force-thumb");
 	}
-	putchar('\n');
+	idx += len;
       }
     }
   }
   fflush(stdout);
 }
+// where
+static void *print_address(void *, const char *tag, void *data) {
+  if (strcmp(tag, "insn") == 0)
+    printf("0x%08x:\t", data);
+}
 #endif

 #define BCI(len, pop, push, special, islocal, islocal_n, isstore, local_n, local_type) \
@@ -7128,7 +7123,7 @@
 #endif

 #ifdef T2EE_PRINT_COMPILATION
-  if (t2ee_print_compilation) {
+  if (t2ee_print_compilation || PrintAssembly) {
     fprintf(stderr, "Compiling %d %c%c %s\n",
 	compiled_methods,
 	method->is_synchronized() ? 'S' : ' ',
@@ -7205,7 +7200,7 @@

 #ifdef T2EE_PRINT_DISASS
   if (DISASS_AFTER == 0 || compiled_methods >= DISASS_AFTER)
-    if (t2ee_print_disass)
+    if (PrintAssembly)
 	Thumb2_disass(&jinfo_str);
 #endif

@@ -7380,7 +7375,7 @@
   t2ee_print_statistics = getenv("T2EE_PRINT_STATISTICS");
 #endif
 #ifdef T2EE_PRINT_DISASS
-  t2ee_print_disass = getenv("T2EE_PRINT_DISASS");
+  PrintAssembly |= getenv("T2EE_PRINT_DISASS") != NULL;
 #endif
 #ifdef T2EE_PRINT_REGUSAGE
   t2ee_print_regusage = getenv("T2EE_PRINT_REGUSAGE");
@@ -7772,33 +7767,19 @@
   mov_imm(&codebuf, ARM_R3, (u32)Thumb2_Handle_Exception_NoRegs);
   mov_reg(&codebuf, ARM_PC, ARM_R3);

+  // Disassemble the codebuf we just created.  For debugging
+  if (PrintAssembly) {
+    Hsdis hsdis;
+    hsdis.decode_instructions(cb->hp, cb->hp + codebuf.idx * 2,
+			      print_address, NULL, NULL, stdout,
+			      "force-thumb");
+    putchar('\n');
+  }
+
   Thumb2_Clear_Cache(cb->hp, cb->hp + codebuf.idx * 2);
   cb->hp += codebuf.idx * 2;

   thumb2_codebuf = cb;
-
-#if 0 // Disassemble the codebuf we just created.  For debugging
-  Opcodes opcodes;
-  if (t2ee_print_disass) {
-    struct disassemble_info info;
-    info.arch = bfd_arch_arm;
-    opcodes.disassemble_init_for_target(&info);
-    opcodes.init_disassemble_info(&info, stdout, (fprintf_ftype)fprintf);
-    info.endian = BFD_ENDIAN_LITTLE;
-    info.endian_code = BFD_ENDIAN_LITTLE;
-    info.buffer = (bfd_byte *)codebuf.codebuf;
-    info.buffer_vma = (bfd_vma)codebuf.codebuf;
-    info.buffer_length = codebuf.idx * sizeof(short);
-    info.disassembler_options = (char *)"force-thumb";
-    int len;
-    for (unsigned int i = 0; i < codebuf.idx * sizeof(short); i += len) {
-      printf("0x%08x:\t", ((int)codebuf.codebuf)+i);
-      len = opcodes.print_insn_little_arm(((bfd_vma)codebuf.codebuf)+i, &info);
-      if (len == -1) len = 2;
-      putchar('\n');
-    }
-  }
-#endif
 }

 #endif // THUMB2EE
diff -r 8c63d311e066 patches/arm-hsdis.patch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/arm-hsdis.patch	Fri Jan 20 10:43:58 2012 -0500
@@ -0,0 +1,90 @@
+2012-01-20  Andrew Haley  <aph at redhat.com>
+
+	* Makefile (ARCH): Add entry for armv7l.
+	(CFLAGS): Enable debugging.
+	($(LIBRARIES)): Pass CFLAGS to sub-make.
+	* hsdis.c: Include string.h.
+	(parse_caller_options): Fix strncmp bug.
+	(native_arch_name): Add entry for ARM.
+
+diff -u openjdk/hotspot/src/share/tools/hsdis/hsdis.c ../icedtea6/openjdk/hotspot/src/share/tools/hsdis/hsdis.c
+--- openjdk/hotspot/src/share/tools/hsdis/hsdis.c	2011-11-14 17:07:33.000000000 -0500
++++ openjdk/hotspot/src/share/tools/hsdis/hsdis.c	2012-01-20 10:21:28.000000000 -0500
+@@ -22,8 +22,6 @@
+  *
+  */
+
+-#include "precompiled.hpp"
+-
+ /* hsdis.c -- dump a range of addresses as native instructions
+    This implements the plugin protocol required by the
+    HotSpot PrintAssembly option.
+@@ -37,6 +35,8 @@
+ #include <dis-asm.h>
+ #include <inttypes.h>
+
++#include <string.h>
++
+ #ifndef bool
+ #define bool int
+ #define true 1
+@@ -358,7 +358,7 @@
+       if (plen > mach_size)  plen = mach_size;
+       strncpy(mach_option, p, plen);
+       mach_option[plen] = '\0';
+-    } else if (plen > 6 && strncmp(p, "hsdis-", 6)) {
++    } 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  */
+@@ -420,6 +420,9 @@
+ #ifdef LIBARCH_sparcv9
+     res = "sparc:v9b";
+ #endif
++#ifdef LIBARCH_arm
++    res = "arm";
++#endif
+   if (res == NULL)
+     res = "architecture not set in Makefile!";
+   return res;
+diff -u openjdk/hotspot/src/share/tools/hsdis/Makefile openjdk/hotspot/src/share/tools/hsdis/Makefile
+--- openjdk/hotspot/src/share/tools/hsdis/Makefile	2011-11-14 17:07:33.000000000 -0500
++++ openjdk/hotspot/src/share/tools/hsdis/Makefile	2012-01-20 10:20:32.000000000 -0500
+@@ -68,14 +68,18 @@
+ CONFIGURE_ARGS= --host=$(MINGW) --target=$(MINGW)
+ else
+ CPU             = $(shell uname -m)
++ifeq		($(CPU),armv7l)
++ARCH=arm
++else
+ ARCH1=$(CPU:x86_64=amd64)
+ ARCH=$(ARCH1:i686=i386)
+ CFLAGS/i386	+= -m32
+ CFLAGS/sparc	+= -m32
+ CFLAGS/sparcv9	+= -m64
+ CFLAGS/amd64	+= -m64
++endif
+ CFLAGS		+= $(CFLAGS/$(ARCH))
+-CFLAGS		+= -fPIC
++CFLAGS		+= -fPIC -g
+ OS		= linux
+ LIB_EXT		= .so
+ CC 		= gcc
+@@ -118,7 +122,7 @@
+ BINUTILSDIR	= $(shell cd $(BINUTILS);pwd)
+ endif
+
+-CPPFLAGS	+= -I$(BINUTILSDIR)/include -I$(BINUTILS)/bfd -I$(TARGET_DIR)/bfd
++CPPFLAGS	+= -I$(BINUTILSDIR)/include -I$(BINUTILSDIR)/bfd -I$(TARGET_DIR)/bfd
+ CPPFLAGS	+= -DLIBARCH_$(LIBARCH) -DLIBARCH=\"$(LIBARCH)\" -DLIB_EXT=\"$(LIB_EXT)\"
+
+ TARGET_DIR	= build/$(OS)-$(JDKARCH)
+@@ -145,7 +149,7 @@
+ demo: $(TARGET) $(DEMO_TARGET)
+
+ $(LIBRARIES): $(TARGET_DIR) $(TARGET_DIR)/Makefile
+-	if [ ! -f $@ ]; then cd $(TARGET_DIR); make all-opcodes; fi
++	if [ ! -f $@ ]; then cd $(TARGET_DIR); make all-opcodes "CFLAGS=$(CFLAGS)"; fi
+
+ $(TARGET_DIR)/Makefile:
+ 	(cd $(TARGET_DIR); CC=$(CC) CFLAGS="$(CFLAGS)" $(BINUTILSDIR)/configure --disable-nls $(CONFIGURE_ARGS))



More information about the distro-pkg-dev mailing list