]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Merge r6102/6103:
authorJulian Seward <jseward@acm.org>
Tue, 17 Oct 2006 01:23:07 +0000 (01:23 +0000)
committerJulian Seward <jseward@acm.org>
Tue, 17 Oct 2006 01:23:07 +0000 (01:23 +0000)
A new module ("Initial Image"), whose purpose is to set up the
client's initial memory and register state before running it.  On
Linux this does all the stack/auxv/envp stuff which was previously
done in m_main.  On AIX5 the kernel prepares the process' initial
image, so there's nothing to be done there.  But LD_PRELOAD doesn't
work on AIX5, so m_initimg sets up the client so as to start by
running a short bit of code which gets the kernel to load in the core
and tool preloads and then start the client.

As a result of this, m_main gets a lot shorter and cleaner.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@6251

coregrind/m_initimg/initimg-aix5.c [new file with mode: 0644]
coregrind/m_initimg/initimg-linux.c
coregrind/m_initimg/simple_huffman.c [new file with mode: 0644]

diff --git a/coregrind/m_initimg/initimg-aix5.c b/coregrind/m_initimg/initimg-aix5.c
new file mode 100644 (file)
index 0000000..a1d3b16
--- /dev/null
@@ -0,0 +1,519 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Startup: create initial process image on AIX5                ---*/
+/*---                                               initimg-aix5.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2006-2006 OpenWorks LLP
+      info@open-works.co.uk
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program 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 for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_vkiscnums.h"
+#include "pub_core_debuglog.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcfile.h"
+#include "pub_core_libcproc.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_clientstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_mallocfree.h"
+#include "pub_core_machine.h"
+#include "pub_core_ume.h"
+#include "pub_core_options.h"
+#include "pub_core_threadstate.h"     /* ThreadArchState */
+#include "pub_core_tooliface.h"       /* VG_TRACK */
+#include "pub_core_trampoline.h" /* VG_(ppc32_aix5_do_preloads_then_start_client) */
+#include "pub_core_syscall.h"         // VG_(do_syscall1)
+#include "pub_core_initimg.h"         /* self */
+
+#include "simple_huffman.c"
+
+#if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5)
+#error "This should only be compiled on AIX"
+#endif
+
+
+static void diagnose_load_failure ( void );
+
+/* --- Create the client's initial memory image. --- */
+
+ClientInitImgInfo
+   VG_(setup_client_initial_image)(
+      /*IN*/ HChar** argv,
+      /*IN*/ HChar** envp,
+      /*IN*/ HChar*  toolname,
+      /*IN*/ Addr    clstack_top,
+      /*IN*/ SizeT   clstack_max_size
+   )
+{
+   ClientInitImgInfo ciii;
+
+   /* Set up an AIX5PreloadPage structure with the names of
+
+         $VALGRIND_LIB/PLATFORM/vgpreload_core.so
+         $VALGRIND_LIB/PLATFORM/vgpreload_TOOL.so, if it exists
+         xxx in "LD_PRELOAD=xxx", if it exists
+
+      The client is started by running (on the simulator, of course)
+      VG_(ppc{32,64}_aix5_do_preloads_then_start_client), which uses
+      __loadx/_kload to load these .so's.  When the preloading is
+      done, various guest registers are restored to what they are
+      really supposed to be at client startup, so these values too are
+      stored in the AIX5PreloadPage.  Finally, we jump to the client's
+      entry point address. 
+   */
+   const HChar* _so               = ".so";
+   const HChar* vgpreload_        = "vgpreload_";
+   const HChar* vgpreload_core_so = "vgpreload_core.so";
+   const HChar* errmsg_str 
+                   = "valgrind: FATAL: core/tool/LD_PRELOAD= "
+                     "preload failed.\n";
+   Int    plcore_len,  pltool_len, ld_pre_len, errmsg_len;
+   HChar *plcore_str, *pltool_str, *ld_pre_str;
+   Bool   have_tool_so, have_ld_pre;
+
+   AIX5PreloadPage* pp;
+   UChar*           pc;
+   Int              szB, szPG;
+   SysRes           sres;
+
+   vg_assert( toolname );
+   pltool_len = VG_(strlen)( VG_(libdir) ) 
+                + 1 /*slash*/
+                + VG_(strlen)(VG_PLATFORM)
+                + 1 /*slash*/
+                + VG_(strlen)( vgpreload_ )
+                + VG_(strlen)( toolname )
+                + VG_(strlen)( _so )
+                + 1 /*NUL*/;
+   vg_assert(pltool_len > 0);
+   pltool_str = VG_(malloc)( pltool_len );
+   pltool_str[0] = 0;
+   VG_(strcat)( pltool_str, VG_(libdir) );
+   VG_(strcat)( pltool_str, "/" );
+   VG_(strcat)( pltool_str, VG_PLATFORM );
+   VG_(strcat)( pltool_str, "/" );
+   VG_(strcat)( pltool_str, vgpreload_ );
+   VG_(strcat)( pltool_str, toolname );
+   VG_(strcat)( pltool_str, _so );
+   vg_assert( pltool_str[pltool_len-1] == 0);
+   vg_assert( VG_(strlen)(pltool_str) == pltool_len-1 );
+
+   plcore_len = VG_(strlen)( VG_(libdir) ) 
+                + 1 /*slash*/
+                + VG_(strlen)(VG_PLATFORM)
+                + 1 /*slash*/
+                + VG_(strlen)( vgpreload_core_so )
+                + 1 /*NUL*/;
+   vg_assert(plcore_len > 0);
+   plcore_str = VG_(malloc)( plcore_len );
+   plcore_str[0] = 0;
+   VG_(strcat)( plcore_str, VG_(libdir) );
+   VG_(strcat)( plcore_str, "/" );
+   VG_(strcat)( plcore_str, VG_PLATFORM );
+   VG_(strcat)( plcore_str, "/" );
+   VG_(strcat)( plcore_str, vgpreload_core_so );
+   vg_assert( plcore_str[plcore_len-1] == 0 );
+   vg_assert( VG_(strlen)(plcore_str) == plcore_len-1 );
+
+   errmsg_len = VG_(strlen)( errmsg_str )
+                + 1 /*NUL*/;
+
+   ld_pre_str = VG_(getenv)("LD_PRELOAD");
+   if (ld_pre_str && VG_(strlen)(ld_pre_str) > 0) {
+      have_ld_pre = True;
+      ld_pre_len  = VG_(strlen)(ld_pre_str) + 1/*NUL*/;
+      ld_pre_str = VG_(malloc)( ld_pre_len );
+      ld_pre_str[0] = 0;
+      VG_(strcat)( ld_pre_str, VG_(getenv)("LD_PRELOAD") );
+      vg_assert( ld_pre_str[ld_pre_len-1] == 0);
+      vg_assert( VG_(strlen)( ld_pre_str ) == ld_pre_len - 1 );
+   } else {
+      have_ld_pre = False;
+      ld_pre_len  = 0;
+      ld_pre_str  = NULL;
+   }
+
+   VG_(debugLog)(1, "initimg", "plcore_str = '%s'\n", plcore_str );
+   VG_(debugLog)(1, "initimg", "pltool_str = '%s'\n", pltool_str );
+   VG_(debugLog)(1, "initimg", "ld_pre_str = '%s'\n", ld_pre_str );
+
+   if (0 != VG_(access)(plcore_str, True,False,True))
+      VG_(err_config_error)("Can't find core preload "
+                            "(vgpreload_core.so)");
+
+   have_tool_so = 0 == VG_(access)(pltool_str, True,False,True);
+
+   /* Figure out how much space is needed for an AIX5PreloadInfo
+      followed by the three preload strings. */
+
+   vg_assert((sizeof(AIX5PreloadPage) % 4) == 0); /* paranoia */
+
+   szB = sizeof(AIX5PreloadPage) + plcore_len 
+                                 + (have_tool_so ? pltool_len : 0)
+                                 + (have_ld_pre ? ld_pre_len : 0)
+                                 + errmsg_len;
+   szPG = VG_PGROUNDUP(szB+1) / VKI_PAGE_SIZE;
+   VG_(debugLog)(2, "initimg", "preload page size: %d bytes, %d pages\n", szB, szPG);
+
+   vg_assert(szB > 0);
+   vg_assert(szB < szPG * VKI_PAGE_SIZE);
+
+   /* We'll need szPG pages of anonymous, rw-, client space (needs w
+      so we can write it here) */
+   sres = VG_(am_mmap_anon_float_client)
+             ( szPG * VKI_PAGE_SIZE, VKI_PROT_READ|VKI_PROT_WRITE);
+   if (sres.isError)
+      VG_(err_config_error)("Can't allocate client page(s) "
+                            "for preload info");
+   pp = (AIX5PreloadPage*)sres.res;
+
+   VG_(debugLog)(2, "initimg", "preload page allocation succeeded at %p\n", pp);
+
+   /* Zero out the initial structure. */
+   VG_(memset)(pp, 0, sizeof(AIX5PreloadPage));
+
+   pc = (UChar*)pp;
+   pc += sizeof(AIX5PreloadPage);
+   VG_(memcpy)(pc, plcore_str, plcore_len);
+   pp->off_preloadcorename = pc - (UChar*)pp;
+   pc += plcore_len;
+   if (have_tool_so) {
+      VG_(memcpy)(pc, pltool_str, pltool_len);
+      pp->off_preloadtoolname = pc - (UChar*)pp;
+      pc += pltool_len;
+   }
+   if (have_ld_pre) {
+      VG_(memcpy)(pc, ld_pre_str, ld_pre_len);
+      pp->off_ld_preloadname = pc - (UChar*)pp;
+      pc += ld_pre_len;
+   }
+   VG_(memcpy)(pc, errmsg_str, errmsg_len);
+   pp->off_errmsg = pc - (UChar*)pp;
+   pp->len_errmsg = errmsg_len - 1; /* -1: skip terminating NUL */
+
+   vg_assert(pc <= ((UChar*)pp) - 1 + szPG * VKI_PAGE_SIZE);
+
+   VG_(free)(plcore_str);
+   VG_(free)(pltool_str);
+
+   /* Fill in all the other preload page fields that we can right
+      now. */
+#  if defined(VGP_ppc32_aix5)
+   vg_assert(__NR_AIX5___loadx != __NR_AIX5_UNKNOWN);
+   pp->nr_load = __NR_AIX5___loadx;
+#  else /* defined(VGP_ppc64_aix5) */
+   vg_assert(__NR_AIX5_kload != __NR_AIX5_UNKNOWN);
+   pp->nr_load = __NR_AIX5_kload;
+#  endif
+
+   vg_assert(__NR_AIX5_kwrite  != __NR_AIX5_UNKNOWN);
+   pp->nr_kwrite = __NR_AIX5_kwrite;   /* kwrite */
+
+   vg_assert(__NR_AIX5__exit   != __NR_AIX5_UNKNOWN);
+   pp->nr__exit = __NR_AIX5__exit;    /* _exit */
+
+   pp->p_diagnose_load_failure = &diagnose_load_failure;
+
+   ciii.preloadpage = pp;
+   ciii.intregs37 = 0; /* filled in in m_main.c */
+   return ciii;
+}
+
+
+/* --- Finalise the initial image and register state. --- */
+
+static UChar unz_page[VKI_PAGE_SIZE];
+
+static UInt compute_adler32 ( void* addr, UWord len )
+{
+   UInt   s1 = 1;
+   UInt   s2 = 0;
+   UChar* buf = (UChar*)addr;
+   while (len > 0) {
+      s1 += buf[0];
+      s2 += s1;
+      s1 %= 65521;
+      s2 %= 65521;
+      len--;
+      buf++;
+   }
+   return (s2 << 16) + s1;
+}
+
+void VG_(finalise_thread1state)( /*MOD*/ThreadArchState* arch,
+                                 ClientInitImgInfo ciii )
+{
+  UInt adler32_act;
+   SysRes sres;
+   /* On AIX we get a block of 37 words telling us the initial state
+      for (GPR0 .. GPR31, PC, CR, LR, CTR, XER), and we start with all
+      the other registers zeroed. */
+
+#  if defined(VGP_ppc32_aix5)
+
+   vg_assert(0 == sizeof(VexGuestPPC32State) % 8);
+
+   /* Zero out the initial state, and set up the simulated FPU in a
+      sane way. */
+   LibVEX_GuestPPC32_initialise(&arch->vex);
+
+   /* Zero out the shadow area. */
+   VG_(memset)(&arch->vex_shadow, 0, sizeof(VexGuestPPC32State));
+
+#  else /* defined(VGP_ppc64_aix5) */
+
+   vg_assert(0 == sizeof(VexGuestPPC64State) % 8);
+
+   /* Zero out the initial state, and set up the simulated FPU in a
+      sane way. */
+   LibVEX_GuestPPC64_initialise(&arch->vex);
+
+   /* Zero out the shadow area. */
+   VG_(memset)(&arch->vex_shadow, 0, sizeof(VexGuestPPC64State));
+
+#  endif
+
+   /* ciii.intregs37 contains the integer register state as it needs
+      to be at client startup.  These values are supplied by the
+      launcher.  The 37 regs are:initial values from launcher for:
+      GPR0 .. GPR31, PC, CR, LR, CTR, XER. */
+
+   /* Put essential stuff into the new state. */
+   arch->vex.guest_GPR0  =  (UWord)ciii.intregs37[0];
+   arch->vex.guest_GPR1  =  (UWord)ciii.intregs37[1];
+   arch->vex.guest_GPR2  =  (UWord)ciii.intregs37[2];
+   arch->vex.guest_GPR3  =  (UWord)ciii.intregs37[3];
+   arch->vex.guest_GPR4  =  (UWord)ciii.intregs37[4];
+   arch->vex.guest_GPR5  =  (UWord)ciii.intregs37[5];
+   arch->vex.guest_GPR6  =  (UWord)ciii.intregs37[6];
+   arch->vex.guest_GPR7  =  (UWord)ciii.intregs37[7];
+   arch->vex.guest_GPR8  =  (UWord)ciii.intregs37[8];
+   arch->vex.guest_GPR9  =  (UWord)ciii.intregs37[9];
+   arch->vex.guest_GPR10 =  (UWord)ciii.intregs37[10];
+   arch->vex.guest_GPR11 =  (UWord)ciii.intregs37[11];
+   arch->vex.guest_GPR12 =  (UWord)ciii.intregs37[12];
+   arch->vex.guest_GPR13 =  (UWord)ciii.intregs37[13];
+   arch->vex.guest_GPR14 =  (UWord)ciii.intregs37[14];
+   arch->vex.guest_GPR15 =  (UWord)ciii.intregs37[15];
+   arch->vex.guest_GPR16 =  (UWord)ciii.intregs37[16];
+   arch->vex.guest_GPR17 =  (UWord)ciii.intregs37[17];
+   arch->vex.guest_GPR18 =  (UWord)ciii.intregs37[18];
+   arch->vex.guest_GPR19 =  (UWord)ciii.intregs37[19];
+   arch->vex.guest_GPR20 =  (UWord)ciii.intregs37[20];
+   arch->vex.guest_GPR21 =  (UWord)ciii.intregs37[21];
+   arch->vex.guest_GPR22 =  (UWord)ciii.intregs37[22];
+   arch->vex.guest_GPR23 =  (UWord)ciii.intregs37[23];
+   arch->vex.guest_GPR24 =  (UWord)ciii.intregs37[24];
+   arch->vex.guest_GPR25 =  (UWord)ciii.intregs37[25];
+   arch->vex.guest_GPR26 =  (UWord)ciii.intregs37[26];
+   arch->vex.guest_GPR27 =  (UWord)ciii.intregs37[27];
+   arch->vex.guest_GPR28 =  (UWord)ciii.intregs37[28];
+   arch->vex.guest_GPR29 =  (UWord)ciii.intregs37[29];
+   arch->vex.guest_GPR30 =  (UWord)ciii.intregs37[30];
+   arch->vex.guest_GPR31 =  (UWord)ciii.intregs37[31];
+
+   arch->vex.guest_CIA      = (UWord)ciii.intregs37[32+0];
+   arch->vex.guest_LR       = (UWord)ciii.intregs37[32+2];
+   arch->vex.guest_CTR      = (UWord)ciii.intregs37[32+3];
+
+#  if defined(VGP_ppc32_aix5)
+
+   LibVEX_GuestPPC32_put_CR(  (UWord)ciii.intregs37[32+1], &arch->vex );
+   LibVEX_GuestPPC32_put_XER( (UWord)ciii.intregs37[32+4], &arch->vex );
+
+   /* Set the cache line size (KLUDGE) */
+   VG_(machine_ppc32_set_clszB)( 128 );
+
+#  else /* defined(VGP_ppc64_aix5) */
+
+   LibVEX_GuestPPC64_put_CR(  (UWord)ciii.intregs37[32+1], &arch->vex );
+   LibVEX_GuestPPC64_put_XER( (UWord)ciii.intregs37[32+4], &arch->vex );
+
+   /* Set the cache line size (KLUDGE) */
+   VG_(machine_ppc64_set_clszB)( 128 );
+
+#  endif
+
+   /* Fix up the client's command line.  Its argc/v/envp is in r3/4/5
+      (32-bit AIX) or r14/15/16 (64-bit AIX).  but that is for the
+      Valgrind invokation as a whole.  Hence we need to decrement argc
+      and advance argv to step over the args for Valgrind, and the
+      name of the Valgrind tool exe bogusly inserted by the launcher
+      (hence the "+1"). */
+
+#  if defined(VGP_ppc32_aix5)
+
+   vg_assert(arch->vex.guest_GPR3 >= 1 + VG_(args_for_valgrind).used);
+   arch->vex.guest_GPR3 -= (1 + VG_(args_for_valgrind).used);
+   arch->vex.guest_GPR4 += sizeof(UWord) * (1 + VG_(args_for_valgrind).used);
+
+#  else /* defined(VGP_ppc64_aix5) */
+
+   vg_assert(arch->vex.guest_GPR14 >= 1 + VG_(args_for_valgrind).used);
+   arch->vex.guest_GPR14 -= (1 + VG_(args_for_valgrind).used);
+   arch->vex.guest_GPR15 += sizeof(UWord) * (1 + VG_(args_for_valgrind).used);
+
+#  endif
+
+   /* At this point the guest register state is correct for client
+      startup.  However, that's not where we want to start; in fact we
+      want to start at VG_(ppc{3,64}2_aix5_do_preloads_then_start_client),
+      passing it ciii.preloadpage in r3.  This will load the core/tool
+      preload .so's, then restore r2-r10 from what's stashed in the
+      preloadpage, and then start the client really.  Hence: */
+
+   /* Save r2-r10 and the client start point in preloadpage */
+   ciii.preloadpage->r2  = (ULong)arch->vex.guest_GPR2;
+   ciii.preloadpage->r3  = (ULong)arch->vex.guest_GPR3;
+   ciii.preloadpage->r4  = (ULong)arch->vex.guest_GPR4;
+   ciii.preloadpage->r5  = (ULong)arch->vex.guest_GPR5;
+   ciii.preloadpage->r6  = (ULong)arch->vex.guest_GPR6;
+   ciii.preloadpage->r7  = (ULong)arch->vex.guest_GPR7;
+   ciii.preloadpage->r8  = (ULong)arch->vex.guest_GPR8;
+   ciii.preloadpage->r9  = (ULong)arch->vex.guest_GPR9;
+   ciii.preloadpage->r10 = (ULong)arch->vex.guest_GPR10;
+   ciii.preloadpage->client_start = (ULong)arch->vex.guest_CIA;
+
+
+#  if defined(VGP_ppc32_aix5)
+
+   /* Set up to start at VG_(ppc32_aix5_do_preloads_then_start_client) */
+   arch->vex.guest_CIA = (UWord)&VG_(ppc32_aix5_do_preloads_then_start_client);
+
+#  else /* defined(VGP_ppc64_aix5) */
+
+   /* Set up to start at VG_(ppc64_aix5_do_preloads_then_start_client) */
+   arch->vex.guest_CIA = (UWord)&VG_(ppc64_aix5_do_preloads_then_start_client);
+
+#  endif
+
+   arch->vex.guest_GPR3 = (UWord)ciii.preloadpage;
+
+   /* The rest of the preloadpage fields will already have been filled
+      in by VG_(setup_client_initial_image).  So we're done. */
+
+   /* Finally, decompress the page compressed by the launcher.  We
+      can't do this any earlier, because the page is (effectively)
+      decompressed in place, which trashes ciii.intregs37.  So we have
+      to wait till this point, at which we're done with ciii.intregs37
+      (to be precise, with what it points at). */
+   VG_(debugLog)(1, "initimg", "decompressing page at %p\n", 
+                    (void*)ciii.compressed_page);
+   vg_assert(VG_IS_PAGE_ALIGNED(ciii.compressed_page));
+
+   Huffman_Uncompress( (void*)ciii.compressed_page, unz_page,
+                       VKI_PAGE_SIZE, VKI_PAGE_SIZE );
+   adler32_act = compute_adler32(unz_page, VKI_PAGE_SIZE);
+
+   VG_(debugLog)(1, "initimg", 
+                    "decompress done, adler32s: act 0x%x, exp 0x%x\n",
+                    adler32_act, ciii.adler32_exp );
+
+   VG_(memcpy)((void*)ciii.compressed_page, unz_page, VKI_PAGE_SIZE);
+
+   VG_(debugLog)(1, "initimg", "copy back done\n");
+
+   /* Tell the tool that we just wrote to the registers. */
+   VG_TRACK( post_reg_write, Vg_CoreStartup, /*tid*/1, /*offset*/0,
+             sizeof(VexGuestArchState));
+
+   /* Determine the brk limit. */
+   VG_(debugLog)(1, "initimg", "establishing current brk ..\n");
+   vg_assert(__NR_AIX5_sbrk != __NR_AIX5_UNKNOWN);
+   sres = VG_(do_syscall1)(__NR_AIX5_sbrk, 0);
+   vg_assert(sres.err == 0); /* assert no error */
+   VG_(brk_base) = VG_(brk_limit) = sres.res;
+   VG_(debugLog)(1, "initimg", ".. brk = %p\n", (void*)VG_(brk_base));
+}
+
+
+/* --- Diagnose preload failures. --- */
+
+/* This is a nasty but effective kludge.  The address of the following
+   function is put into the preload page.  So, if a preload failure
+   happens, we call here to get helpful info printed out (the call
+   site is in m_trampoline.S).  This is a dirty hack (1) because
+   diagnose_load_failure runs on the simulated CPU, not the real one
+   and (2) because it induces a libc dependency.  Oh well. */
+
+/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
+#include <stdlib.h>
+#include <sys/ldr.h>
+/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
+
+static void diagnose_load_failure ( void )
+{
+#  define NBUF 1024
+   UChar buf[NBUF];
+   VG_(debugLog)(0, "initimg", "Diagnosing load failure\n");
+   if (sizeof(void*) == 8) {
+      VG_(debugLog)(0, "initimg", "Can't safely do loadquery() "
+                                  "in 64-bit mode.  Sorry.\n");
+      /* because this requires dynamic linking to be working (IIRC)
+         and it isn't; the tool file's dynamic linking was never done,
+         because it was loaded by the bootstrap stub, which simply did
+         sys_kload() but didn't make usla do the relevant
+         relocations. */
+   } else {
+      UChar** p;
+      Int r = loadquery(L_GETMESSAGES, buf, NBUF);
+      VG_(debugLog)(0, "initimg", "loadquery returned %d (0 = success)\n", r);
+      p = (UChar**)(&buf[0]);
+      for (; *p; p++)
+         VG_(debugLog)(0, "initimg", "\"%s\"\n", *p);
+      VG_(debugLog)(0, "initimg", "Use /usr/sbin/execerror to make "
+                                  "sense of above string(s)\n");
+      VG_(debugLog)(0, "initimg", "See also comments at the bottom of\n");
+      VG_(debugLog)(0, "initimg", "coregrind/m_initimg/"
+                                  "initimg-aix5.c (in Valgrind sources)\n");
+   }
+#  undef NBUF
+}
+
+/* Take the strings that this prints out and feed them
+   to /usr/sbin/execerror.  For example, it might print
+
+     (ld 3 1 __libc_freeres /foo/bar/ppc32-aix5/vgpreload_core.so
+
+   in which case 
+
+     $ execerror xyzzy \
+          "(ld 3 1 __libc_freeres /foo/bar/ppc32-aix5/vgpreload_core.so"
+
+   gets you
+
+     Could not load program xyzzy:
+     rtld: 0712-001 Symbol __libc_freeres was referenced
+     from module /foo/bar/ppc32-aix5/vgpreload_core.so(), 
+        but a runtime definition
+            of the symbol was not found.
+*/
+
+/*--------------------------------------------------------------------*/
+/*---                                               initimg-aix5.c ---*/
+/*--------------------------------------------------------------------*/
index ddef6c1a6284621be2e76bae8c39ed9115dd3de2..5f04857aac74328ebc6b2bf3151fdb19c8b5d2c2 100644 (file)
@@ -187,7 +187,7 @@ static void load_client ( /*OUT*/ExeInfo* info,
       executable.  This is needed for attaching to GDB. */
    res = VG_(open)(exe_name, VKI_O_RDONLY, VKI_S_IRUSR);
    if (!res.isError)
-      VG_(cl_exec_fd) = res.val;
+      VG_(cl_exec_fd) = res.res;
 
    /* Copy necessary bits of 'info' that were filled in */
    *client_ip  = info->init_ip;
@@ -809,7 +809,7 @@ static void setup_client_dataseg ( SizeT max_size )
              VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC
           );
    vg_assert(!sres.isError);
-   vg_assert(sres.val == anon_start);
+   vg_assert(sres.res == anon_start);
 }
 
 
diff --git a/coregrind/m_initimg/simple_huffman.c b/coregrind/m_initimg/simple_huffman.c
new file mode 100644 (file)
index 0000000..f9f3bb5
--- /dev/null
@@ -0,0 +1,513 @@
+/*************************************************************************
+* Name:        huffman.c
+* Author:      Marcus Geelnard
+* Description: Huffman coder/decoder implementation.
+* Reentrant:   Yes
+* $Id: huffman.c,v 1.6 2004/12/14 18:59:40 marcus256 Exp $
+*
+* This is a very straight forward implementation of a Huffman coder and
+* decoder.
+*
+* Primary flaws with this primitive implementation are:
+*  - Slow bit stream implementation
+*  - Fairly slow decoding (slower than encoding)
+*  - Maximum tree depth of 32 (the coder aborts if any code exceeds a
+*    size of 32 bits). If I'm not mistaking, this should not be possible
+*    unless the input buffer is larger than 2^32 bytes, which is not
+*    supported by the coder anyway (max 2^32-1 bytes can be specified with
+*    an unsigned 32-bit integer).
+*
+* On the other hand, there are a few advantages of this implementation:
+*  - The Huffman tree is stored in a very compact form, requiring only
+*    12 bits per symbol (for 8 bit symbols), meaning a maximum of 384
+*    bytes overhead.
+*  - The Huffman coder does quite well in situations where the data is
+*    noisy, in which case most dictionary based coders run into problems.
+*
+* Possible improvements (probably not worth it):
+*  - Partition the input data stream into blocks, where each block has
+*    its own Huffman tree. With variable block sizes, it should be
+*    possible to find locally optimal Huffman trees, which in turn could
+*    reduce the total size.
+*  - Allow for a few different predefined Huffman trees, which could
+*    reduce the size of a block even further.
+*-------------------------------------------------------------------------
+* Copyright (c) 2003-2004 Marcus Geelnard
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would
+*    be appreciated but is not required.
+*
+* 2. Altered source versions must be plainly marked as such, and must not
+*    be misrepresented as being the original software.
+*
+* 3. This notice may not be removed or altered from any source
+*    distribution.
+*
+* Marcus Geelnard
+* marcus.geelnard at home.se
+*************************************************************************/
+
+/* Modified May 06 by Julian Seward for use in Valgrind.
+   - changed integral types to V's versions (UInt, UChar etc)
+   - added initialisation in _Huffman_WriteBits, as described in
+     comment in that function.
+*/
+
+/*************************************************************************
+* Types used for Huffman coding
+*************************************************************************/
+
+typedef struct {
+    UInt Symbol;
+    UInt Count;
+    UInt Code;
+    UInt Bits;
+} huff_sym_t;
+
+typedef struct {
+    UChar *BytePtr;
+    UInt  BitPos;
+} huff_bitstream_t;
+
+
+
+/*************************************************************************
+*                           INTERNAL FUNCTIONS                           *
+*************************************************************************/
+
+
+/*************************************************************************
+* _Huffman_InitBitstream() - Initialize a bitstream.
+*************************************************************************/
+
+static void _Huffman_InitBitstream( huff_bitstream_t *stream,
+    UChar *buf )
+{
+    stream->BytePtr  = buf;
+    stream->BitPos   = 0;
+}
+
+
+/*************************************************************************
+* _Huffman_ReadBits() - Read bits from a bitstream.
+*************************************************************************/
+
+static UInt _Huffman_ReadBits( huff_bitstream_t *stream,
+    UInt bits )
+{
+    UInt  x, bit, count;
+    UChar *buf;
+
+    /* Get current stream state */
+    buf = stream->BytePtr;
+    bit = stream->BitPos;
+
+    /* Extract bits */
+    x = 0;
+    for( count = 0; count < bits; ++ count )
+    {
+        x = (x<<1) + (*buf & (1<<(7-bit)) ? 1 : 0);
+        bit = (bit+1) & 7;
+        if( !bit )
+        {
+            ++ buf;
+        }
+    }
+
+    /* Store new stream state */
+    stream->BytePtr = buf;
+    stream->BitPos  = bit;
+
+    return x;
+}
+
+
+/*************************************************************************
+* _Huffman_WriteBits() - Write bits to a bitstream.
+*************************************************************************/
+
+static void _Huffman_WriteBits( huff_bitstream_t *stream, UInt x,
+    UInt bits )
+{
+    UInt  bit, count;
+    UChar *buf;
+    UInt  mask;
+
+    /* Get current stream state */
+    buf = stream->BytePtr;
+    bit = stream->BitPos;
+
+    /* Append bits */
+    mask = 1 << (bits-1);
+    for( count = 0; count < bits; ++ count )
+    {
+        /* If we're starting a new byte, zero it out, so that the
+           resulting byte sequence looks completely defined from
+           Valgrind's point of view.  If this doesn't happen then the
+           last byte in the stream may look partially undefined. */
+        if (bit == 0)
+           *buf = 0;
+        *buf = (*buf & (0xff^(1<<(7-bit)))) +
+               ((x & mask ? 1 : 0) << (7-bit));
+        x <<= 1;
+        bit = (bit+1) & 7;
+        if( !bit )
+        {
+            ++ buf;
+        }
+    }
+
+    /* Store new stream state */
+    stream->BytePtr = buf;
+    stream->BitPos  = bit;
+}
+
+
+/*************************************************************************
+* _Huffman_Hist() - Calculate (sorted) histogram for a block of data.
+*************************************************************************/
+
+static void _Huffman_Hist( UChar *in, huff_sym_t *sym,
+    UInt size )
+{
+    Int k, swaps;
+    huff_sym_t tmp;
+
+    /* Clear/init histogram */
+    for( k = 0; k < 256; ++ k )
+    {
+        sym[k].Symbol = k;
+        sym[k].Count  = 0;
+        sym[k].Code   = 0;
+        sym[k].Bits   = 0;
+    }
+
+    /* Build histogram */
+    for( k = size; k; -- k )
+    {
+        sym[ *in ++ ].Count ++;
+    }
+
+    /* Sort histogram - most frequent symbol first (bubble sort) */
+    do
+    {
+        swaps = 0;
+        for( k = 0; k < 255; ++ k )
+        {
+            if( sym[k].Count < sym[k+1].Count )
+            {
+                tmp      = sym[k];
+                sym[k]   = sym[k+1];
+                sym[k+1] = tmp;
+                swaps    = 1;
+            }
+        }
+    }
+    while( swaps );
+}
+
+
+/*************************************************************************
+* _Huffman_MakeTree() - Generate a Huffman tree.
+*************************************************************************/
+
+static void _Huffman_MakeTree( huff_sym_t *sym, huff_bitstream_t *stream,
+    UInt code, UInt bits, UInt first,
+    UInt last )
+{
+    UInt k, size, size_a, size_b, last_a, first_b;
+
+    /* Is this a leaf node? */
+    if( first == last )
+    {
+        /* Append symbol to tree description */
+        _Huffman_WriteBits( stream, 1, 1 );
+        _Huffman_WriteBits( stream, sym[first].Symbol, 8 );
+
+        /* Store code info in symbol array */
+        sym[first].Code = code;
+        sym[first].Bits = bits;
+        return;
+    }
+    else
+    {
+        /* This was not a leaf node */
+        _Huffman_WriteBits( stream, 0, 1 );
+    }
+
+    /* Total size of interval */
+    size = 0;
+    for( k = first; k <= last; ++ k )
+    {
+        size += sym[k].Count;
+    }
+
+    /* Find size of branch a */
+    size_a = 0;
+    for( k = first; size_a < ((size+1)>>1) && k < last; ++ k )
+    {
+        size_a += sym[k].Count;
+    }
+
+    /* Non-empty branch? */
+    if( size_a > 0 )
+    {
+        /* Continue branching */
+        _Huffman_WriteBits( stream, 1, 1 );
+
+        /* Branch a cut in histogram */
+        last_a  = k-1;
+
+        /* Create branch a */
+        _Huffman_MakeTree( sym, stream, (code<<1)+0, bits+1,
+                               first, last_a );
+    }
+    else
+    {
+        /* This was an empty branch */
+        _Huffman_WriteBits( stream, 0, 1 );
+    }
+
+    /* Size of branch b */
+    size_b = size - size_a;
+
+    /* Non-empty branch? */
+    if( size_b > 0 )
+    {
+        /* Continue branching */
+        _Huffman_WriteBits( stream, 1, 1 );
+
+        /* Branch b cut in histogram */
+        first_b = k;
+
+        /* Create branch b */
+        _Huffman_MakeTree( sym, stream, (code<<1)+1, bits+1,
+                               first_b, last );
+    }
+    else
+    {
+        /* This was an empty branch */
+        _Huffman_WriteBits( stream, 0, 1 );
+    }
+}
+
+
+/*************************************************************************
+* _Huffman_RecoverTree() - Recover a Huffman tree from a bitstream.
+*************************************************************************/
+
+static void _Huffman_RecoverTree( huff_sym_t *sym,
+    huff_bitstream_t *stream, UInt code, UInt bits,
+    UInt *symnum )
+{
+    UInt symbol;
+
+    /* Is this a leaf node? */
+    if( _Huffman_ReadBits( stream, 1 ) )
+    {
+        /* Get symbol from tree description */
+        symbol = _Huffman_ReadBits( stream, 8 );
+
+        /* Store code info in symbol array */
+        sym[*symnum].Symbol = symbol;
+        sym[*symnum].Code   = code;
+        sym[*symnum].Bits   = bits;
+
+        /* Increase symbol counter */
+        *symnum = *symnum + 1;
+
+        return;
+    }
+
+    /* Non-empty branch? */
+    if( _Huffman_ReadBits( stream, 1 ) )
+    {
+        /* Create branch a */
+        _Huffman_RecoverTree( sym, stream, (code<<1)+0, bits+1,
+                              symnum );
+    }
+
+    /* Non-empty branch? */
+    if( _Huffman_ReadBits( stream, 1 ) )
+    {
+        /* Create branch b */
+        _Huffman_RecoverTree( sym, stream, (code<<1)+1, bits+1,
+                              symnum );
+    }
+}
+
+
+
+
+/*************************************************************************
+*                            PUBLIC FUNCTIONS                            *
+*************************************************************************/
+
+
+/*************************************************************************
+* Huffman_Compress() - Compress a block of data using a Huffman coder.
+*  in     - Input (uncompressed) buffer.
+*  out    - Output (compressed) buffer. This buffer must be 384 bytes
+*           larger than the input buffer.
+*  insize - Number of input bytes.
+* The function returns the size of the compressed data.
+*************************************************************************/
+static
+Int Huffman_Compress( UChar *in, UChar *out,
+    UInt insize )
+{
+    huff_sym_t       sym[ 256 ], tmp;
+    huff_bitstream_t stream;
+    UInt     k, total_bytes, swaps, symbol, last_symbol;
+
+    /* Do we have anything to compress? */
+    if( insize < 1 ) return 0;
+
+    /* Initialize bitstream */
+    _Huffman_InitBitstream( &stream, out );
+
+    /* Calculate and sort histogram for input data */
+    _Huffman_Hist( in, sym, insize );
+
+    /* Find number of used symbols */
+    for( last_symbol = 255; sym[last_symbol].Count == 0; -- last_symbol );
+
+    /* Special case: In order to build a correct tree, we need at least
+       two symbols (otherwise we get zero-bit representations). */
+    if( last_symbol == 0 ) ++ last_symbol;
+
+    /* Build Huffman tree */
+    _Huffman_MakeTree( sym, &stream, 0, 0, 0, last_symbol );
+
+    /* Was any code > 32 bits? (we do not handle that at present) */
+    for( k = 0; k < 255; ++ k )
+    {
+        if( sym[k].Bits > 32 )
+        {
+            return 0;
+        }
+    }
+
+    /* Sort histogram - first symbol first (bubble sort) */
+    do
+    {
+        swaps = 0;
+        for( k = 0; k < 255; ++ k )
+        {
+            if( sym[k].Symbol > sym[k+1].Symbol )
+            {
+                tmp      = sym[k];
+                sym[k]   = sym[k+1];
+                sym[k+1] = tmp;
+                swaps    = 1;
+            }
+        }
+    }
+    while( swaps );
+
+    /* Encode input stream */
+    for( k = 0; k < insize; ++ k )
+    {
+        symbol = in[ k ];
+        _Huffman_WriteBits( &stream, sym[symbol].Code,
+                            sym[symbol].Bits );
+    }
+
+    /* Calculate size of output data */
+    total_bytes = (Int)(stream.BytePtr - out);
+    if( stream.BitPos > 0 )
+    {
+        ++ total_bytes;
+    }
+
+    return total_bytes;
+}
+
+
+
+/*************************************************************************
+* Huffman_Uncompress() - Uncompress a block of data using a Huffman
+* decoder.
+*  in      - Input (compressed) buffer.
+*  out     - Output (uncompressed) buffer. This buffer must be large
+*            enough to hold the uncompressed data.
+*  insize  - Number of input bytes.
+*  outsize - Number of output bytes.
+*************************************************************************/
+static
+void Huffman_Uncompress( UChar *in, UChar *out,
+    UInt insize, UInt outsize )
+{
+    huff_sym_t       sym[ 256 ], tmp;
+    huff_bitstream_t stream;
+    UInt     k, m, symbol_count, swaps;
+    UChar    *buf;
+    UInt     bits, delta_bits, new_bits, code;
+
+    /* Do we have anything to decompress? */
+    if( insize < 1 ) return;
+
+    /* Initialize bitstream */
+    _Huffman_InitBitstream( &stream, in );
+
+    /* Clear tree/histogram */
+    for( k = 0; k < 256; ++ k )
+    {
+        sym[k].Bits = 0x7fffffff;
+    }
+
+    /* Recover Huffman tree */
+    symbol_count = 0;
+    _Huffman_RecoverTree( sym, &stream, 0, 0, &symbol_count );
+
+    /* Sort histogram - shortest code first (bubble sort) */
+    do
+    {
+        swaps = 0;
+        for( k = 0; k < symbol_count-1; ++ k )
+        {
+            if( sym[k].Bits > sym[k+1].Bits )
+            {
+                tmp      = sym[k];
+                sym[k]   = sym[k+1];
+                sym[k+1] = tmp;
+                swaps    = 1;
+            }
+        }
+    }
+    while( swaps );
+
+    /* Decode input stream */
+    buf = out;
+    for( k = 0; k < outsize; ++ k )
+    {
+        /* Search tree for matching code */
+        bits = 0;
+        code = 0;
+        for( m = 0; m < symbol_count; ++ m )
+        {
+            delta_bits = sym[m].Bits - bits;
+            if( delta_bits )
+            {
+                new_bits = _Huffman_ReadBits( &stream, delta_bits );
+                code = code | (new_bits << (32-bits-delta_bits));
+                bits = sym[m].Bits;
+            }
+            if( code == (sym[m].Code << (32-sym[m].Bits)) )
+            {
+                *buf ++ = (UChar) sym[m].Symbol;
+                break;
+            }
+        }
+    }
+}