]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
A very simple dynamic translator built on Vex, for the purpose of
authorJulian Seward <jseward@acm.org>
Sat, 12 Feb 2005 13:02:24 +0000 (13:02 +0000)
committerJulian Seward <jseward@acm.org>
Sat, 12 Feb 2005 13:02:24 +0000 (13:02 +0000)
debugging Vex using the binary-search-switchback technique

git-svn-id: svn://svn.valgrind.org/vex/trunk@889

VEX/switchback/Makefile [new file with mode: 0644]
VEX/switchback/switchback [new file with mode: 0755]
VEX/switchback/switchback.c [new file with mode: 0644]
VEX/switchback/test_hello.c [new file with mode: 0644]

diff --git a/VEX/switchback/Makefile b/VEX/switchback/Makefile
new file mode 100644 (file)
index 0000000..545dcde
--- /dev/null
@@ -0,0 +1,6 @@
+
+all: switchback.c
+       gcc -Wall -O -g -o switchback switchback.c ../libvex.a
+
+clean:
+       rm -f switchback switchback.o
diff --git a/VEX/switchback/switchback b/VEX/switchback/switchback
new file mode 100755 (executable)
index 0000000..210432c
Binary files /dev/null and b/VEX/switchback/switchback differ
diff --git a/VEX/switchback/switchback.c b/VEX/switchback/switchback.c
new file mode 100644 (file)
index 0000000..c5c7868
--- /dev/null
@@ -0,0 +1,356 @@
+
+/* HOW TO USE
+
+Compile test file (eg test_hello.c) to a .o
+
+It must have an entry point called "entry" immediately preceded by the
+bytes 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88, so the entry point can
+be found.
+
+It must have ***NO RELOCATIONS*** -  objdump -r file.o shows none
+
+*/
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "../pub/libvex_basictypes.h"
+#include "../pub/libvex_guest_x86.h"
+#include "../pub/libvex_guest_amd64.h"
+#include "../pub/libvex.h"
+
+
+static Int n_bbs_done = 0;
+
+/* For providing services. */
+static HWord serviceFn ( HWord arg1, HWord arg2 )
+{
+   switch (arg1) {
+      case 0: /* EXIT */
+         printf("---STOP---\n");
+         printf("serviceFn:EXIT\n");
+        printf("%d bbs simulated\n", n_bbs_done);
+         exit(0);
+      case 1: /* PUTC */
+         putchar(arg2);
+         return 0;
+      case 2: /* MALLOC */
+         return (HWord)malloc(arg2);
+      default:
+         assert(0);
+   }
+}
+
+
+#if defined(__i386__)
+#  define VexGuestState             VexGuestX86State
+#  define LibVEX_Guest_initialise   LibVEX_GuestX86_initialise
+#  define VexArch                   VexArchX86
+#  define VexSubArch                VexSubArchX86_sse1
+#  define GuestPC                   guest_EIP
+#else
+#   error "Unknown arch"
+#endif
+
+#define TEST_FLAGS (1<<7) //|(1<<0)
+
+
+/* guest state */
+UInt gstack[50000];
+VexGuestState gst;
+VexControl vcon;
+
+/* only used for the switchback transition */
+/* i386: helper1 = &gst, helper2 = %EFLAGS */
+HWord sb_helper1 = 0;
+HWord sb_helper2 = 0;
+
+/* translation cache */
+#define N_TRANS_CACHE 100000
+#define N_TRANS_TABLE 1000
+
+ULong trans_cache[N_TRANS_CACHE];
+VexGuestExtents trans_table [N_TRANS_TABLE];
+ULong*          trans_tableP[N_TRANS_TABLE];
+
+Int trans_cache_used = 0;
+Int trans_table_used = 0;
+
+static Bool chase_into_not_ok ( Addr64 dst ) { return False; }
+
+/* -------------------- */
+#if defined(__i386__)
+
+/* continue execution on the real CPU (never returns) */
+extern void switchback_asm(void);
+asm(
+"switchback_asm:\n"
+"   movl sb_helper1, %eax\n"  // eax = guest state ptr
+"   movl  16(%eax), %esp\n"   // switch stacks
+"   pushl 56(%eax)\n"         // push continuation addr
+"   movl sb_helper2, %ebx\n"  // get eflags
+"   pushl %ebx\n"             // eflags:CA
+"   pushl 0(%eax)\n"          //  EAX:eflags:CA
+"   movl 4(%eax), %ecx\n" 
+"   movl 8(%eax), %edx\n" 
+"   movl 12(%eax), %ebx\n" 
+"   movl 20(%eax), %ebp\n"
+"   movl 24(%eax), %esi\n"
+"   movl 28(%eax), %edi\n"
+"   popl %eax\n"
+"   popfl\n"
+"   ret\n"
+);
+void switchback ( void )
+{
+   sb_helper1 = (HWord)&gst;
+   sb_helper2 = LibVEX_GuestX86_get_eflags(&gst);
+   switchback_asm(); // never returns
+}
+
+#else
+#   error "Unknown arch (switchback)"
+#endif
+
+/* -------------------- */
+static HWord f, gp, res;
+extern void run_translation_asm(void);
+asm(
+"run_translation_asm:\n"
+"   pushal\n"
+"   movl gp, %ebp\n"
+"   movl f, %eax\n"
+"   call *%eax\n"
+"   movl %eax, res\n"
+"   popal\n"
+"   ret\n"
+);
+
+void run_translation ( HWord translation )
+{
+   if (0)
+      printf(" run translation %p\n", (void*)translation );
+   f = translation;
+   gp = (HWord)&gst;
+   run_translation_asm();
+   gst.GuestPC = res;
+   n_bbs_done ++;
+}
+
+HWord find_translation ( Addr64 guest_addr )
+{
+   Int i;
+   HWord res;
+   if (0)
+      printf("find translation %p ... ", ULong_to_Ptr(guest_addr));
+   for (i = 0; i < trans_table_used; i++)
+     if (trans_table[i].base[0] == guest_addr)
+        break;
+   if (i == trans_table_used) {
+      if (0) printf("none\n");
+      return 0; /* not found */
+   }
+   res = (HWord)trans_tableP[i];
+   if (0) printf("%p\n", (void*)res);
+   return res;
+}
+
+#define N_TRANSBUF 5000
+static UChar transbuf[N_TRANSBUF];
+void make_translation ( Addr64 guest_addr, Bool verbose )
+{
+   VexTranslateResult tres;
+   Int trans_used, i, ws_needed;
+   assert(trans_table_used < N_TRANS_TABLE);
+   if (0)
+      printf("make translation %p\n", ULong_to_Ptr(guest_addr));
+   tres
+      = LibVEX_Translate ( 
+           VexArch, VexSubArch,
+           VexArch, VexSubArch,
+           ULong_to_Ptr(guest_addr), guest_addr,
+           chase_into_not_ok,
+           &trans_table[trans_table_used],
+           transbuf, N_TRANSBUF, &trans_used,
+           NULL,          /* instrument1 */
+           NULL,          /* instrument2 */
+           False,         /* cleanup after instrument */
+           NULL, /* access checker */
+           verbose ? TEST_FLAGS : 0
+        );
+   assert(tres == VexTransOK);
+   ws_needed = (trans_used+7) / 8;
+   assert(ws_needed > 0);
+   assert(trans_cache_used + ws_needed < N_TRANS_CACHE);
+
+   for (i = 0; i < trans_used; i++) {
+     HChar* dst = ((HChar*)(&trans_cache[trans_cache_used])) + i;
+     HChar* src = (HChar*)(&transbuf[i]);
+     *dst = *src;
+   }
+
+   trans_tableP[trans_table_used] = &trans_cache[trans_cache_used];
+   trans_table_used++;
+   trans_cache_used += ws_needed;
+}
+
+
+static Int    stopAfter = 0;
+static UChar* image     = NULL;
+static Int    imageSz   = 0;
+static UChar* entry     = NULL;
+
+
+__attribute__ ((noreturn))
+static
+void failure_exit ( void )
+{
+   fprintf(stdout, "VEX did failure_exit.  Bye.\n");
+   exit(1);
+}
+
+static
+void log_bytes ( HChar* bytes, Int nbytes )
+{
+   fwrite ( bytes, 1, nbytes, stdout );
+}
+
+
+/* run simulated code forever (it will exit by calling
+   serviceFn(0)). */
+static void run_simulator ( void )
+{
+   static Addr64 last_guest = 0;
+   Addr64 next_guest;
+   HWord next_host;
+   while (1) {
+      if (n_bbs_done == stopAfter) {
+         printf("---begin SWITCHBACK at %d---\n", n_bbs_done);
+        if (last_guest)
+            make_translation(last_guest,True);
+         printf("---  end SWITCHBACK at %d---\n", n_bbs_done);
+         switchback();
+         assert(0); /*NOTREACHED*/
+      }
+
+      next_guest = gst.GuestPC;
+
+      if (next_guest == Ptr_to_ULong(&serviceFn)) {
+         /* "do" the function call to serviceFn */
+#        if defined(__i386__)
+         {
+            HWord esp = gst.guest_ESP;
+            gst.guest_EIP = *(UInt*)(esp+0);
+            gst.guest_EAX = serviceFn( *(UInt*)(esp+4), *(UInt*)(esp+8) );
+            gst.guest_ESP = esp+4;
+            next_guest = gst.guest_EIP;
+         }
+#        else
+#        error "Unknown arch"
+#        endif
+      }
+
+      next_host = find_translation(next_guest);
+      if (next_host == 0) {
+         make_translation(next_guest,False);
+         next_host = find_translation(next_guest);
+        assert(next_host != 0);
+      }
+      last_guest = next_guest;
+      run_translation(next_host);
+   }
+}
+
+
+static void usage ( void )
+{
+   printf("usage: switchback file.o #bbs\n");
+   exit(1);
+}
+
+int main ( Int argc, HChar** argv )
+{
+   HChar* oname;
+   FILE* f;
+   Int n, i;
+
+   struct stat buf;
+
+   if (argc != 3) 
+      usage();
+
+   oname = argv[1];
+   stopAfter = atoi(argv[2]);
+
+   if (stat(oname, &buf)) {
+      printf("switchback: can't stat %s\n", oname);
+      return 1;
+   }
+
+   imageSz = (Int)buf.st_size;
+   printf("stopAfter = %d\n", stopAfter);
+   printf("file size is %d\n", imageSz);
+
+   /* Get the file aboard and find the entry point */
+   image = malloc(imageSz);
+   assert(image);
+
+   f = fopen(oname, "r");
+   assert(f);
+   n = fread(image, 1, imageSz, f);
+   assert(n == imageSz);
+   fclose(f);
+
+   assert(imageSz > 12);
+   entry = NULL;
+   for (n = 0; n < imageSz - 8; n++) {
+     if (image[n+0] == 0x11 
+         && image[n+1] == 0x22
+         && image[n+2] == 0x33
+         && image[n+3] == 0x44
+         && image[n+4] == 0x55
+         && image[n+5] == 0x66
+         && image[n+6] == 0x77
+         && image[n+7] == 0x88
+        ) {
+       entry = &image[n+8];
+       break;
+     }
+   }
+
+   if (!entry) {
+      printf("switchback: can't find entry point\n");
+      exit(1);
+   }
+
+   printf("switchback: entry bytes are: ");
+   for (i = 0; i < 4; i++)
+     printf("0x%02x ", (Int)entry[i]);
+
+   LibVEX_default_VexControl(&vcon);
+   vcon.guest_max_insns=1; //50;
+   vcon.guest_chase_thresh=0;
+   LibVEX_Init( failure_exit, log_bytes, 1, False, &vcon );
+   LibVEX_Guest_initialise(&gst);
+
+   /* set up as if a call to the entry point passing serviceFn as 
+      the one and only parameter */
+#  if defined(__i386__)
+   gst.guest_EIP = (UInt)entry;
+   gst.guest_ESP = (UInt)&gstack[25000];
+   *(UInt*)(gst.guest_ESP+4) = (UInt)serviceFn;
+   *(UInt*)(gst.guest_ESP+0) = 0x12345678;
+#  else
+#  error "Unknown arch"
+#  endif
+
+   printf("\n---START---\n");
+
+   run_simulator();
+
+   return 0;
+}
diff --git a/VEX/switchback/test_hello.c b/VEX/switchback/test_hello.c
new file mode 100644 (file)
index 0000000..9fa15f8
--- /dev/null
@@ -0,0 +1,39 @@
+
+
+static void bar ( void*(*service)(int,int) )
+{
+  int i;
+  for (i = 0; i < 100000; i++) ;
+  service(1, 'h');
+  service(1, 'e');
+  service(1, 'l');
+  service(1, 'l');
+  service(1, 'o');
+  service(1, '\n');
+}
+
+asm(
+"nop\n"
+"nop\n"
+"nop\n"
+"nop\n"
+"nop\n"
+"nop\n"
+"nop\n"
+"nop\n"
+".align 8\n"
+".byte 0x11\n"
+".byte 0x22\n"
+".byte 0x33\n"
+".byte 0x44\n"
+".byte 0x55\n"
+".byte 0x66\n"
+".byte 0x77\n"
+".byte 0x88\n"
+);
+void entry ( void*(*service)(int,int) )
+{
+  bar(service);
+  service(0,0);
+}
+