summaryrefslogtreecommitdiff
path: root/coregrind/m_initimg
diff options
context:
space:
mode:
Diffstat (limited to 'coregrind/m_initimg')
-rw-r--r--coregrind/m_initimg/.svn/entries64
-rw-r--r--coregrind/m_initimg/.svn/format1
-rw-r--r--coregrind/m_initimg/.svn/text-base/initimg-aix5.c.svn-base545
-rw-r--r--coregrind/m_initimg/.svn/text-base/initimg-linux.c.svn-base1074
-rw-r--r--coregrind/m_initimg/.svn/text-base/simple_huffman.c.svn-base513
-rw-r--r--coregrind/m_initimg/initimg-aix5.c545
-rw-r--r--coregrind/m_initimg/initimg-linux.c1074
-rw-r--r--coregrind/m_initimg/simple_huffman.c513
8 files changed, 4329 insertions, 0 deletions
diff --git a/coregrind/m_initimg/.svn/entries b/coregrind/m_initimg/.svn/entries
new file mode 100644
index 0000000..20b61af
--- /dev/null
+++ b/coregrind/m_initimg/.svn/entries
@@ -0,0 +1,64 @@
+8
+
+dir
+9703
+svn://svn.valgrind.org/valgrind/trunk/coregrind/m_initimg
+svn://svn.valgrind.org/valgrind
+
+
+
+2009-03-15T23:25:38.213170Z
+9416
+njn
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+a5019735-40e9-0310-863c-91ae7b9d1cf9
+
+initimg-aix5.c
+file
+
+
+
+
+2009-03-13T17:30:26.000000Z
+a38099b9822df1bc1c5fa08e184475bc
+2009-03-10T22:02:09.669944Z
+9344
+njn
+
+simple_huffman.c
+file
+
+
+
+
+2009-03-13T17:30:26.000000Z
+e5442f0e3ffe3d211f42828904a4aa92
+2006-10-17T01:23:07.242425Z
+6251
+sewardj
+
+initimg-linux.c
+file
+
+
+
+
+2009-04-30T16:44:05.000000Z
+d739fd681ebb41781549d983021cd7ad
+2009-03-15T23:25:38.213170Z
+9416
+njn
+
diff --git a/coregrind/m_initimg/.svn/format b/coregrind/m_initimg/.svn/format
new file mode 100644
index 0000000..45a4fb7
--- /dev/null
+++ b/coregrind/m_initimg/.svn/format
@@ -0,0 +1 @@
+8
diff --git a/coregrind/m_initimg/.svn/text-base/initimg-aix5.c.svn-base b/coregrind/m_initimg/.svn/text-base/initimg-aix5.c.svn-base
new file mode 100644
index 0000000..24ca1bc
--- /dev/null
+++ b/coregrind/m_initimg/.svn/text-base/initimg-aix5.c.svn-base
@@ -0,0 +1,545 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Startup: create initial process image on AIX5 ---*/
+/*--- initimg-aix5.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2006-2009 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.
+
+ Neither the names of the U.S. Department of Energy nor the
+ University of California nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without prior written permission.
+*/
+
+#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_xarray.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. --- */
+
+IIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo iicii )
+{
+ /* Set up an AIX5PreloadPage structure with the names of
+
+ $VALGRIND_LIB/vgpreload_core_PLATFORM.so
+ $VALGRIND_LIB/vgpreload_TOOL_PLATFORM.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* core = "core";
+ 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;
+
+ IIFinaliseImageInfo iifii;
+ VG_(memset)( &iifii, 0, sizeof(iifii) );
+
+ /* this can happen, if m_main decides to NULL it out */
+ if (VG_(args_the_exename) == NULL)
+ VG_(err_missing_prog)();
+
+ vg_assert( iicii.toolname );
+ pltool_len = VG_(strlen)( VG_(libdir) )
+ + 1 /*slash*/
+ + VG_(strlen)( vgpreload_ )
+ + VG_(strlen)( iicii.toolname )
+ + 1 /*dash*/
+ + VG_(strlen)(VG_PLATFORM)
+ + VG_(strlen)( _so )
+ + 1 /*NUL*/;
+ vg_assert(pltool_len > 0);
+ pltool_str = VG_(malloc)( "initimg-aix5.ici.1", pltool_len );
+ pltool_str[0] = 0;
+ VG_(strcat)( pltool_str, VG_(libdir) );
+ VG_(strcat)( pltool_str, "/" );
+ VG_(strcat)( pltool_str, vgpreload_ );
+ VG_(strcat)( pltool_str, iicii.toolname );
+ VG_(strcat)( pltool_str, "-" );
+ VG_(strcat)( pltool_str, VG_PLATFORM );
+ 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)( vgpreload_ )
+ + VG_(strlen)( core )
+ + 1 /*dash*/
+ + VG_(strlen)(VG_PLATFORM)
+ + VG_(strlen)(_so)
+ + 1 /*NUL*/;
+ vg_assert(plcore_len > 0);
+ plcore_str = VG_(malloc)( "initimg-aix5.ici.2", plcore_len );
+ plcore_str[0] = 0;
+ VG_(strcat)( plcore_str, VG_(libdir) );
+ VG_(strcat)( plcore_str, "/" );
+ VG_(strcat)( plcore_str, vgpreload_ );
+ VG_(strcat)( plcore_str, core );
+ VG_(strcat)( plcore_str, "-" );
+ VG_(strcat)( plcore_str, VG_PLATFORM );
+ VG_(strcat)( plcore_str, _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)( "initimg-aix5.ici.3", 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-<platform>.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;
+
+ iifii.preloadpage = pp;
+ iifii.intregs37 = iicii.intregs37;
+ iifii.initial_client_SP = iicii.intregs37[1]; /* r1 */
+ iifii.compressed_page = VG_PGROUNDDN((Addr)iicii.bootblock);
+ iifii.adler32_exp = iicii.adler32_exp;
+ iifii.clstack_max_size = 0; /* we don't know yet */
+ return iifii;
+}
+
+
+/* --- 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;
+}
+
+/* Just before starting the client, we may need to make final
+ adjustments to its initial image. Also we need to set up the VEX
+ guest state for thread 1 (the root thread) and copy in essential
+ starting values. This is handed the IIFinaliseImageInfo created by
+ VG_(ii_create_image).
+*/
+void VG_(ii_finalise_image)( IIFinaliseImageInfo iifii )
+{
+ 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. */
+
+ ThreadArchState* arch = &VG_(threads)[1].arch;
+
+# if defined(VGP_ppc32_aix5)
+
+ vg_assert(0 == sizeof(VexGuestPPC32State) % 16);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestPPC32_initialise(&arch->vex);
+
+ /* Zero out the shadow areas. */
+ VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestPPC32State));
+ VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestPPC32State));
+
+# else /* defined(VGP_ppc64_aix5) */
+
+ vg_assert(0 == sizeof(VexGuestPPC64State) % 16);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestPPC64_initialise(&arch->vex);
+
+ /* Zero out the shadow areas. */
+ VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestPPC64State));
+ VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestPPC64State));
+
+# endif
+
+ /* iifii.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)iifii.intregs37[0];
+ arch->vex.guest_GPR1 = (UWord)iifii.intregs37[1];
+ arch->vex.guest_GPR2 = (UWord)iifii.intregs37[2];
+ arch->vex.guest_GPR3 = (UWord)iifii.intregs37[3];
+ arch->vex.guest_GPR4 = (UWord)iifii.intregs37[4];
+ arch->vex.guest_GPR5 = (UWord)iifii.intregs37[5];
+ arch->vex.guest_GPR6 = (UWord)iifii.intregs37[6];
+ arch->vex.guest_GPR7 = (UWord)iifii.intregs37[7];
+ arch->vex.guest_GPR8 = (UWord)iifii.intregs37[8];
+ arch->vex.guest_GPR9 = (UWord)iifii.intregs37[9];
+ arch->vex.guest_GPR10 = (UWord)iifii.intregs37[10];
+ arch->vex.guest_GPR11 = (UWord)iifii.intregs37[11];
+ arch->vex.guest_GPR12 = (UWord)iifii.intregs37[12];
+ arch->vex.guest_GPR13 = (UWord)iifii.intregs37[13];
+ arch->vex.guest_GPR14 = (UWord)iifii.intregs37[14];
+ arch->vex.guest_GPR15 = (UWord)iifii.intregs37[15];
+ arch->vex.guest_GPR16 = (UWord)iifii.intregs37[16];
+ arch->vex.guest_GPR17 = (UWord)iifii.intregs37[17];
+ arch->vex.guest_GPR18 = (UWord)iifii.intregs37[18];
+ arch->vex.guest_GPR19 = (UWord)iifii.intregs37[19];
+ arch->vex.guest_GPR20 = (UWord)iifii.intregs37[20];
+ arch->vex.guest_GPR21 = (UWord)iifii.intregs37[21];
+ arch->vex.guest_GPR22 = (UWord)iifii.intregs37[22];
+ arch->vex.guest_GPR23 = (UWord)iifii.intregs37[23];
+ arch->vex.guest_GPR24 = (UWord)iifii.intregs37[24];
+ arch->vex.guest_GPR25 = (UWord)iifii.intregs37[25];
+ arch->vex.guest_GPR26 = (UWord)iifii.intregs37[26];
+ arch->vex.guest_GPR27 = (UWord)iifii.intregs37[27];
+ arch->vex.guest_GPR28 = (UWord)iifii.intregs37[28];
+ arch->vex.guest_GPR29 = (UWord)iifii.intregs37[29];
+ arch->vex.guest_GPR30 = (UWord)iifii.intregs37[30];
+ arch->vex.guest_GPR31 = (UWord)iifii.intregs37[31];
+
+ arch->vex.guest_CIA = (UWord)iifii.intregs37[32+0];
+ arch->vex.guest_LR = (UWord)iifii.intregs37[32+2];
+ arch->vex.guest_CTR = (UWord)iifii.intregs37[32+3];
+
+# if defined(VGP_ppc32_aix5)
+
+ LibVEX_GuestPPC32_put_CR( (UWord)iifii.intregs37[32+1], &arch->vex );
+ LibVEX_GuestPPC32_put_XER( (UWord)iifii.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)iifii.intregs37[32+1], &arch->vex );
+ LibVEX_GuestPPC64_put_XER( (UWord)iifii.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)
+
+ { UWord n_vargs = VG_(sizeXA)( VG_(args_for_valgrind) );
+ vg_assert(arch->vex.guest_GPR3 >= 1 + n_vargs);
+ arch->vex.guest_GPR3 -= (1 + n_vargs);
+ arch->vex.guest_GPR4 += sizeof(UWord) * (1 + n_vargs);
+ }
+
+# else /* defined(VGP_ppc64_aix5) */
+
+ { UWord n_vargs = VG_(sizeXA)( VG_(args_for_valgrind) );
+ vg_assert(arch->vex.guest_GPR14 >= 1 + n_vargs);
+ arch->vex.guest_GPR14 -= (1 + n_vargs);
+ arch->vex.guest_GPR15 += sizeof(UWord) * (1 + n_vargs);
+ }
+
+# 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{32,64}_aix5_do_preloads_then_start_client),
+ passing it iifii.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 */
+ iifii.preloadpage->r2 = (ULong)arch->vex.guest_GPR2;
+ iifii.preloadpage->r3 = (ULong)arch->vex.guest_GPR3;
+ iifii.preloadpage->r4 = (ULong)arch->vex.guest_GPR4;
+ iifii.preloadpage->r5 = (ULong)arch->vex.guest_GPR5;
+ iifii.preloadpage->r6 = (ULong)arch->vex.guest_GPR6;
+ iifii.preloadpage->r7 = (ULong)arch->vex.guest_GPR7;
+ iifii.preloadpage->r8 = (ULong)arch->vex.guest_GPR8;
+ iifii.preloadpage->r9 = (ULong)arch->vex.guest_GPR9;
+ iifii.preloadpage->r10 = (ULong)arch->vex.guest_GPR10;
+ iifii.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)iifii.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 iifii.intregs37. So we have
+ to wait till this point, at which we're done with iifii.intregs37
+ (to be precise, with what it points at). */
+ VG_(debugLog)(1, "initimg", "decompressing page at %p\n",
+ (void*)iifii.compressed_page);
+ vg_assert(VG_IS_PAGE_ALIGNED(iifii.compressed_page));
+
+ Huffman_Uncompress( (void*)iifii.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, iifii.adler32_exp );
+
+ VG_(memcpy)((void*)iifii.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/vgpreload_core-ppc32-aix5.so
+
+ in which case
+
+ $ execerror xyzzy \
+ "(ld 3 1 __libc_freeres /foo/bar/vgpreload_core-ppc32-aix5.so"
+
+ gets you
+
+ Could not load program xyzzy:
+ rtld: 0712-001 Symbol __libc_freeres was referenced
+ from module /foo/bar/vgpreload_core-ppc32-aix5.so(),
+ but a runtime definition
+ of the symbol was not found.
+*/
+
+/*--------------------------------------------------------------------*/
+/*--- initimg-aix5.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_initimg/.svn/text-base/initimg-linux.c.svn-base b/coregrind/m_initimg/.svn/text-base/initimg-linux.c.svn-base
new file mode 100644
index 0000000..e80dc22
--- /dev/null
+++ b/coregrind/m_initimg/.svn/text-base/initimg-linux.c.svn-base
@@ -0,0 +1,1074 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Startup: create initial process image on Linux ---*/
+/*--- initimg-linux.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2009 Julian Seward
+ jseward@acm.org
+
+ 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_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_xarray.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_syscall.h"
+#include "pub_core_tooliface.h" /* VG_TRACK */
+#include "pub_core_threadstate.h" /* ThreadArchState */
+#include "pub_core_initimg.h" /* self */
+
+/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
+#define _GNU_SOURCE
+#define _FILE_OFFSET_BITS 64
+/* This is for ELF types etc, and also the AT_ constants. */
+#include <elf.h>
+/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
+
+
+/*====================================================================*/
+/*=== Find executable ===*/
+/*====================================================================*/
+
+/* Scan a colon-separated list, and call a function on each element.
+ The string must be mutable, because we insert a temporary '\0', but
+ the string will end up unmodified. (*func) should return True if it
+ doesn't need to see any more.
+
+ This routine will return True if (*func) returns True and False if
+ it reaches the end of the list without that happening.
+*/
+static Bool scan_colsep(char *colsep, Bool (*func)(const char *))
+{
+ char *cp, *entry;
+ int end;
+
+ if (colsep == NULL ||
+ *colsep == '\0')
+ return False;
+
+ entry = cp = colsep;
+
+ do {
+ end = (*cp == '\0');
+
+ if (*cp == ':' || *cp == '\0') {
+ char save = *cp;
+
+ *cp = '\0';
+ if ((*func)(entry)) {
+ *cp = save;
+ return True;
+ }
+ *cp = save;
+ entry = cp+1;
+ }
+ cp++;
+ } while(!end);
+
+ return False;
+}
+
+/* Need a static copy because can't use dynamic mem allocation yet */
+static HChar executable_name_in [VKI_PATH_MAX];
+static HChar executable_name_out[VKI_PATH_MAX];
+
+static Bool match_executable(const char *entry)
+{
+ HChar buf[VG_(strlen)(entry) + VG_(strlen)(executable_name_in) + 3];
+
+ /* empty PATH element means '.' */
+ if (*entry == '\0')
+ entry = ".";
+
+ VG_(snprintf)(buf, sizeof(buf), "%s/%s", entry, executable_name_in);
+
+ // Don't match directories
+ if (VG_(is_dir)(buf))
+ return False;
+
+ // If we match an executable, we choose that immediately. If we find a
+ // matching non-executable we remember it but keep looking for an
+ // matching executable later in the path.
+ if (VG_(access)(buf, True/*r*/, False/*w*/, True/*x*/) == 0) {
+ VG_(strncpy)( executable_name_out, buf, VKI_PATH_MAX-1 );
+ executable_name_out[VKI_PATH_MAX-1] = 0;
+ return True; // Stop looking
+ } else if (VG_(access)(buf, True/*r*/, False/*w*/, False/*x*/) == 0
+ && VG_STREQ(executable_name_out, ""))
+ {
+ VG_(strncpy)( executable_name_out, buf, VKI_PATH_MAX-1 );
+ executable_name_out[VKI_PATH_MAX-1] = 0;
+ return False; // Keep looking
+ } else {
+ return False; // Keep looking
+ }
+}
+
+// Returns NULL if it wasn't found.
+static HChar* find_executable ( HChar* exec )
+{
+ vg_assert(NULL != exec);
+ if (VG_(strchr)(exec, '/')) {
+ // Has a '/' - use the name as is
+ VG_(strncpy)( executable_name_out, exec, VKI_PATH_MAX-1 );
+ } else {
+ // No '/' - we need to search the path
+ HChar* path;
+ VG_(strncpy)( executable_name_in, exec, VKI_PATH_MAX-1 );
+ VG_(memset) ( executable_name_out, 0, VKI_PATH_MAX );
+ path = VG_(getenv)("PATH");
+ scan_colsep(path, match_executable);
+ }
+ return VG_STREQ(executable_name_out, "") ? NULL : executable_name_out;
+}
+
+
+/*====================================================================*/
+/*=== Loading the client ===*/
+/*====================================================================*/
+
+/* Load the client whose name is VG_(argv_the_exename). */
+
+static void load_client ( /*OUT*/ExeInfo* info,
+ /*OUT*/Addr* client_ip,
+ /*OUT*/Addr* client_toc)
+{
+ HChar* exe_name;
+ Int ret;
+ SysRes res;
+
+ vg_assert( VG_(args_the_exename) != NULL);
+ exe_name = find_executable( VG_(args_the_exename) );
+
+ if (!exe_name) {
+ VG_(printf)("valgrind: %s: command not found\n", VG_(args_the_exename));
+ VG_(exit)(127); // 127 is Posix NOTFOUND
+ }
+
+ VG_(memset)(info, 0, sizeof(*info));
+ ret = VG_(do_exec)(exe_name, info);
+ if (ret < 0) {
+ VG_(printf)("valgrind: could not execute '%s'\n", exe_name);
+ VG_(exit)(1);
+ }
+
+ // The client was successfully loaded! Continue.
+
+ /* Get hold of a file descriptor which refers to the client
+ 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.res;
+
+ /* Copy necessary bits of 'info' that were filled in */
+ *client_ip = info->init_ip;
+ *client_toc = info->init_toc;
+ VG_(brk_base) = VG_(brk_limit) = VG_PGROUNDUP(info->brkbase);
+}
+
+
+/*====================================================================*/
+/*=== Setting up the client's environment ===*/
+/*====================================================================*/
+
+/* Prepare the client's environment. This is basically a copy of our
+ environment, except:
+
+ LD_PRELOAD=$VALGRIND_LIB/vgpreload_core-PLATFORM.so:
+ ($VALGRIND_LIB/vgpreload_TOOL-PLATFORM.so:)?
+ $LD_PRELOAD
+
+ If this is missing, then it is added.
+
+ Also, remove any binding for VALGRIND_LAUNCHER=. The client should
+ not be able to see this.
+
+ If this needs to handle any more variables it should be hacked
+ into something table driven. The copy is VG_(malloc)'d space.
+*/
+static HChar** setup_client_env ( HChar** origenv, const HChar* toolname)
+{
+ HChar* preload_core = "vgpreload_core";
+ HChar* ld_preload = "LD_PRELOAD=";
+ HChar* v_launcher = VALGRIND_LAUNCHER "=";
+ Int ld_preload_len = VG_(strlen)( ld_preload );
+ Int v_launcher_len = VG_(strlen)( v_launcher );
+ Bool ld_preload_done = False;
+ Int vglib_len = VG_(strlen)(VG_(libdir));
+
+ HChar** cpp;
+ HChar** ret;
+ HChar* preload_tool_path;
+ Int envc, i;
+
+ /* Alloc space for the vgpreload_core.so path and vgpreload_<tool>.so
+ paths. We might not need the space for vgpreload_<tool>.so, but it
+ doesn't hurt to over-allocate briefly. The 16s are just cautious
+ slop. */
+ Int preload_core_path_len = vglib_len + sizeof(preload_core)
+ + sizeof(VG_PLATFORM) + 16;
+ Int preload_tool_path_len = vglib_len + VG_(strlen)(toolname)
+ + sizeof(VG_PLATFORM) + 16;
+ Int preload_string_len = preload_core_path_len + preload_tool_path_len;
+ HChar* preload_string = VG_(malloc)("initimg-linux.sce.1",
+ preload_string_len);
+ vg_assert(origenv);
+ vg_assert(toolname);
+ vg_assert(preload_string);
+
+ /* Determine if there's a vgpreload_<tool>_<platform>.so file, and setup
+ preload_string. */
+ preload_tool_path = VG_(malloc)("initimg-linux.sce.2", preload_tool_path_len);
+ vg_assert(preload_tool_path);
+ VG_(snprintf)(preload_tool_path, preload_tool_path_len,
+ "%s/vgpreload_%s-%s.so", VG_(libdir), toolname, VG_PLATFORM);
+ if (VG_(access)(preload_tool_path, True/*r*/, False/*w*/, False/*x*/) == 0) {
+ VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so:%s",
+ VG_(libdir), preload_core, VG_PLATFORM, preload_tool_path);
+ } else {
+ VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so",
+ VG_(libdir), preload_core, VG_PLATFORM);
+ }
+ VG_(free)(preload_tool_path);
+
+ VG_(debugLog)(2, "initimg", "preload_string:\n");
+ VG_(debugLog)(2, "initimg", " \"%s\"\n", preload_string);
+
+ /* Count the original size of the env */
+ envc = 0;
+ for (cpp = origenv; cpp && *cpp; cpp++)
+ envc++;
+
+ /* Allocate a new space */
+ ret = VG_(malloc) ("initimg-linux.sce.3",
+ sizeof(HChar *) * (envc+1+1)); /* 1 new entry + NULL */
+ vg_assert(ret);
+
+ /* copy it over */
+ for (cpp = ret; *origenv; )
+ *cpp++ = *origenv++;
+ *cpp = NULL;
+
+ vg_assert(envc == (cpp - ret));
+
+ /* Walk over the new environment, mashing as we go */
+ for (cpp = ret; cpp && *cpp; cpp++) {
+ if (VG_(memcmp)(*cpp, ld_preload, ld_preload_len) == 0) {
+ Int len = VG_(strlen)(*cpp) + preload_string_len;
+ HChar *cp = VG_(malloc)("initimg-linux.sce.4", len);
+ vg_assert(cp);
+
+ VG_(snprintf)(cp, len, "%s%s:%s",
+ ld_preload, preload_string, (*cpp)+ld_preload_len);
+
+ *cpp = cp;
+
+ ld_preload_done = True;
+ }
+ }
+
+ /* Add the missing bits */
+ if (!ld_preload_done) {
+ Int len = ld_preload_len + preload_string_len;
+ HChar *cp = VG_(malloc) ("initimg-linux.sce.5", len);
+ vg_assert(cp);
+
+ VG_(snprintf)(cp, len, "%s%s", ld_preload, preload_string);
+
+ ret[envc++] = cp;
+ }
+
+ /* ret[0 .. envc-1] is live now. */
+ /* Find and remove a binding for VALGRIND_LAUNCHER. */
+ for (i = 0; i < envc; i++)
+ if (0 == VG_(memcmp(ret[i], v_launcher, v_launcher_len)))
+ break;
+
+ if (i < envc) {
+ for (; i < envc-1; i++)
+ ret[i] = ret[i+1];
+ envc--;
+ }
+
+ VG_(free)(preload_string);
+ ret[envc] = NULL;
+
+ return ret;
+}
+
+
+/*====================================================================*/
+/*=== Setting up the client's stack ===*/
+/*====================================================================*/
+
+#ifndef AT_DCACHEBSIZE
+#define AT_DCACHEBSIZE 19
+#endif /* AT_DCACHEBSIZE */
+
+#ifndef AT_ICACHEBSIZE
+#define AT_ICACHEBSIZE 20
+#endif /* AT_ICACHEBSIZE */
+
+#ifndef AT_UCACHEBSIZE
+#define AT_UCACHEBSIZE 21
+#endif /* AT_UCACHEBSIZE */
+
+#ifndef AT_SYSINFO
+#define AT_SYSINFO 32
+#endif /* AT_SYSINFO */
+
+#ifndef AT_SYSINFO_EHDR
+#define AT_SYSINFO_EHDR 33
+#endif /* AT_SYSINFO_EHDR */
+
+#ifndef AT_SECURE
+#define AT_SECURE 23 /* secure mode boolean */
+#endif /* AT_SECURE */
+
+/* Add a string onto the string table, and return its address */
+static char *copy_str(char **tab, const char *str)
+{
+ char *cp = *tab;
+ char *orig = cp;
+
+ while(*str)
+ *cp++ = *str++;
+ *cp++ = '\0';
+
+ if (0)
+ VG_(printf)("copied %p \"%s\" len %lld\n", orig, orig, (Long)(cp-orig));
+
+ *tab = cp;
+
+ return orig;
+}
+
+
+/* ----------------------------------------------------------------
+
+ This sets up the client's initial stack, containing the args,
+ environment and aux vector.
+
+ The format of the stack is:
+
+ higher address +-----------------+ <- clstack_end
+ | |
+ : string table :
+ | |
+ +-----------------+
+ | AT_NULL |
+ - -
+ | auxv |
+ +-----------------+
+ | NULL |
+ - -
+ | envp |
+ +-----------------+
+ | NULL |
+ - -
+ | argv |
+ +-----------------+
+ | argc |
+ lower address +-----------------+ <- sp
+ | undefined |
+ : :
+
+ Allocate and create the initial client stack. It is allocated down
+ from clstack_end, which was previously determined by the address
+ space manager. The returned value is the SP value for the client.
+
+ The client's auxv is created by copying and modifying our own one.
+ As a side effect of scanning our own auxv, some important bits of
+ info are collected:
+
+ VG_(cache_line_size_ppc32) // ppc32 only -- cache line size
+ VG_(have_altivec_ppc32) // ppc32 only -- is Altivec supported?
+
+ ---------------------------------------------------------------- */
+
+struct auxv
+{
+ Word a_type;
+ union {
+ void *a_ptr;
+ Word a_val;
+ } u;
+};
+
+static
+struct auxv *find_auxv(UWord* sp)
+{
+ sp++; // skip argc (Nb: is word-sized, not int-sized!)
+
+ while (*sp != 0) // skip argv
+ sp++;
+ sp++;
+
+ while (*sp != 0) // skip env
+ sp++;
+ sp++;
+
+#if defined(VGA_ppc32) || defined(VGA_ppc64)
+# if defined AT_IGNOREPPC
+ while (*sp == AT_IGNOREPPC) // skip AT_IGNOREPPC entries
+ sp += 2;
+# endif
+#endif
+
+ return (struct auxv *)sp;
+}
+
+static
+Addr setup_client_stack( void* init_sp,
+ char** orig_envp,
+ const ExeInfo* info,
+ UInt** client_auxv,
+ Addr clstack_end,
+ SizeT clstack_max_size )
+{
+ SysRes res;
+ char **cpp;
+ char *strtab; /* string table */
+ char *stringbase;
+ Addr *ptr;
+ struct auxv *auxv;
+ const struct auxv *orig_auxv;
+ const struct auxv *cauxv;
+ unsigned stringsize; /* total size of strings in bytes */
+ unsigned auxsize; /* total size of auxv in bytes */
+ Int argc; /* total argc */
+ Int envc; /* total number of env vars */
+ unsigned stacksize; /* total client stack size */
+ Addr client_SP; /* client stack base (initial SP) */
+ Addr clstack_start;
+ Int i;
+ Bool have_exename;
+
+ vg_assert(VG_IS_PAGE_ALIGNED(clstack_end+1));
+ vg_assert( VG_(args_for_client) );
+
+ /* use our own auxv as a prototype */
+ orig_auxv = find_auxv(init_sp);
+
+ /* ==================== compute sizes ==================== */
+
+ /* first of all, work out how big the client stack will be */
+ stringsize = 0;
+ have_exename = VG_(args_the_exename) != NULL;
+
+ /* paste on the extra args if the loader needs them (ie, the #!
+ interpreter and its argument) */
+ argc = 0;
+ if (info->interp_name != NULL) {
+ argc++;
+ stringsize += VG_(strlen)(info->interp_name) + 1;
+ }
+ if (info->interp_args != NULL) {
+ argc++;
+ stringsize += VG_(strlen)(info->interp_args) + 1;
+ }
+
+ /* now scan the args we're given... */
+ if (have_exename)
+ stringsize += VG_(strlen)( VG_(args_the_exename) ) + 1;
+
+ for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
+ argc++;
+ stringsize += VG_(strlen)( * (HChar**)
+ VG_(indexXA)( VG_(args_for_client), i ))
+ + 1;
+ }
+
+ /* ...and the environment */
+ envc = 0;
+ for (cpp = orig_envp; cpp && *cpp; cpp++) {
+ envc++;
+ stringsize += VG_(strlen)(*cpp) + 1;
+ }
+
+ /* now, how big is the auxv? */
+ auxsize = sizeof(*auxv); /* there's always at least one entry: AT_NULL */
+ for (cauxv = orig_auxv; cauxv->a_type != AT_NULL; cauxv++) {
+ if (cauxv->a_type == AT_PLATFORM)
+ stringsize += VG_(strlen)(cauxv->u.a_ptr) + 1;
+ auxsize += sizeof(*cauxv);
+ }
+
+# if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
+ auxsize += 2 * sizeof(*cauxv);
+# endif
+
+ /* OK, now we know how big the client stack is */
+ stacksize =
+ sizeof(Word) + /* argc */
+ (have_exename ? sizeof(char **) : 0) + /* argc[0] == exename */
+ sizeof(char **)*argc + /* argv */
+ sizeof(char **) + /* terminal NULL */
+ sizeof(char **)*envc + /* envp */
+ sizeof(char **) + /* terminal NULL */
+ auxsize + /* auxv */
+ VG_ROUNDUP(stringsize, sizeof(Word)); /* strings (aligned) */
+
+ if (0) VG_(printf)("stacksize = %d\n", stacksize);
+
+ /* client_SP is the client's stack pointer */
+ client_SP = clstack_end - stacksize;
+ client_SP = VG_ROUNDDN(client_SP, 16); /* make stack 16 byte aligned */
+
+ /* base of the string table (aligned) */
+ stringbase = strtab = (char *)clstack_end
+ - VG_ROUNDUP(stringsize, sizeof(int));
+
+ clstack_start = VG_PGROUNDDN(client_SP);
+
+ /* The max stack size */
+ clstack_max_size = VG_PGROUNDUP(clstack_max_size);
+
+ /* Record stack extent -- needed for stack-change code. */
+ VG_(clstk_base) = clstack_start;
+ VG_(clstk_end) = clstack_end;
+
+ if (0)
+ VG_(printf)("stringsize=%d auxsize=%d stacksize=%d maxsize=0x%x\n"
+ "clstack_start %p\n"
+ "clstack_end %p\n",
+ stringsize, auxsize, stacksize, (Int)clstack_max_size,
+ (void*)clstack_start, (void*)clstack_end);
+
+ /* ==================== allocate space ==================== */
+
+ { SizeT anon_size = clstack_end - clstack_start + 1;
+ SizeT resvn_size = clstack_max_size - anon_size;
+ Addr anon_start = clstack_start;
+ Addr resvn_start = anon_start - resvn_size;
+ SizeT inner_HACK = 0;
+ Bool ok;
+
+ /* So far we've only accounted for space requirements down to the
+ stack pointer. If this target's ABI requires a redzone below
+ the stack pointer, we need to allocate an extra page, to
+ handle the worst case in which the stack pointer is almost at
+ the bottom of a page, and so there is insufficient room left
+ over to put the redzone in. In this case the simple thing to
+ do is allocate an extra page, by shrinking the reservation by
+ one page and growing the anonymous area by a corresponding
+ page. */
+ vg_assert(VG_STACK_REDZONE_SZB >= 0);
+ vg_assert(VG_STACK_REDZONE_SZB < VKI_PAGE_SIZE);
+ if (VG_STACK_REDZONE_SZB > 0) {
+ vg_assert(resvn_size > VKI_PAGE_SIZE);
+ resvn_size -= VKI_PAGE_SIZE;
+ anon_start -= VKI_PAGE_SIZE;
+ anon_size += VKI_PAGE_SIZE;
+ }
+
+ vg_assert(VG_IS_PAGE_ALIGNED(anon_size));
+ vg_assert(VG_IS_PAGE_ALIGNED(resvn_size));
+ vg_assert(VG_IS_PAGE_ALIGNED(anon_start));
+ vg_assert(VG_IS_PAGE_ALIGNED(resvn_start));
+ vg_assert(resvn_start == clstack_end + 1 - clstack_max_size);
+
+# ifdef ENABLE_INNER
+ inner_HACK = 1024*1024; // create 1M non-fault-extending stack
+# endif
+
+ if (0)
+ VG_(printf)("%#lx 0x%lx %#lx 0x%lx\n",
+ resvn_start, resvn_size, anon_start, anon_size);
+
+ /* Create a shrinkable reservation followed by an anonymous
+ segment. Together these constitute a growdown stack. */
+ res = VG_(mk_SysRes_Error)(0);
+ ok = VG_(am_create_reservation)(
+ resvn_start,
+ resvn_size -inner_HACK,
+ SmUpper,
+ anon_size +inner_HACK
+ );
+ if (ok) {
+ /* allocate a stack - mmap enough space for the stack */
+ res = VG_(am_mmap_anon_fixed_client)(
+ anon_start -inner_HACK,
+ anon_size +inner_HACK,
+ VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC
+ );
+ }
+ if ((!ok) || res.isError) {
+ /* Allocation of the stack failed. We have to stop. */
+ VG_(printf)("valgrind: "
+ "I failed to allocate space for the application's stack.\n");
+ VG_(printf)("valgrind: "
+ "This may be the result of a very large --main-stacksize=\n");
+ VG_(printf)("valgrind: setting. Cannot continue. Sorry.\n\n");
+ VG_(exit)(0);
+ }
+
+ vg_assert(ok);
+ vg_assert(!res.isError);
+ }
+
+ /* ==================== create client stack ==================== */
+
+ ptr = (Addr*)client_SP;
+
+ /* --- client argc --- */
+ *ptr++ = argc + (have_exename ? 1 : 0);
+
+ /* --- client argv --- */
+ if (info->interp_name) {
+ *ptr++ = (Addr)copy_str(&strtab, info->interp_name);
+ VG_(free)(info->interp_name);
+ }
+ if (info->interp_args) {
+ *ptr++ = (Addr)copy_str(&strtab, info->interp_args);
+ VG_(free)(info->interp_args);
+ }
+
+ if (have_exename)
+ *ptr++ = (Addr)copy_str(&strtab, VG_(args_the_exename));
+
+ for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
+ *ptr++ = (Addr)copy_str(
+ &strtab,
+ * (HChar**) VG_(indexXA)( VG_(args_for_client), i )
+ );
+ }
+ *ptr++ = 0;
+
+ /* --- envp --- */
+ VG_(client_envp) = (Char **)ptr;
+ for (cpp = orig_envp; cpp && *cpp; ptr++, cpp++)
+ *ptr = (Addr)copy_str(&strtab, *cpp);
+ *ptr++ = 0;
+
+ /* --- auxv --- */
+ auxv = (struct auxv *)ptr;
+ *client_auxv = (UInt *)auxv;
+
+# if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
+ auxv[0].a_type = AT_IGNOREPPC;
+ auxv[0].u.a_val = AT_IGNOREPPC;
+ auxv[1].a_type = AT_IGNOREPPC;
+ auxv[1].u.a_val = AT_IGNOREPPC;
+ auxv += 2;
+# endif
+
+ for (; orig_auxv->a_type != AT_NULL; auxv++, orig_auxv++) {
+
+ /* copy the entry... */
+ *auxv = *orig_auxv;
+
+ /* ...and fix up / examine the copy */
+ switch(auxv->a_type) {
+
+ case AT_IGNORE:
+ case AT_PHENT:
+ case AT_PAGESZ:
+ case AT_FLAGS:
+ case AT_NOTELF:
+ case AT_UID:
+ case AT_EUID:
+ case AT_GID:
+ case AT_EGID:
+ case AT_CLKTCK:
+ case AT_FPUCW:
+ /* All these are pointerless, so we don't need to do
+ anything about them. */
+ break;
+
+ case AT_PHDR:
+ if (info->phdr == 0)
+ auxv->a_type = AT_IGNORE;
+ else
+ auxv->u.a_val = info->phdr;
+ break;
+
+ case AT_PHNUM:
+ if (info->phdr == 0)
+ auxv->a_type = AT_IGNORE;
+ else
+ auxv->u.a_val = info->phnum;
+ break;
+
+ case AT_BASE:
+ auxv->u.a_val = info->interp_base;
+ break;
+
+ case AT_PLATFORM:
+ /* points to a platform description string */
+ auxv->u.a_ptr = copy_str(&strtab, orig_auxv->u.a_ptr);
+ break;
+
+ case AT_ENTRY:
+ auxv->u.a_val = info->entry;
+ break;
+
+ case AT_HWCAP:
+ break;
+
+ case AT_DCACHEBSIZE:
+ case AT_ICACHEBSIZE:
+ case AT_UCACHEBSIZE:
+# if defined(VGP_ppc32_linux)
+ /* acquire cache info */
+ if (auxv->u.a_val > 0) {
+ VG_(machine_ppc32_set_clszB)( auxv->u.a_val );
+ VG_(debugLog)(2, "initimg",
+ "PPC32 cache line size %u (type %u)\n",
+ (UInt)auxv->u.a_val, (UInt)auxv->a_type );
+ }
+# elif defined(VGP_ppc64_linux)
+ /* acquire cache info */
+ if (auxv->u.a_val > 0) {
+ VG_(machine_ppc64_set_clszB)( auxv->u.a_val );
+ VG_(debugLog)(2, "initimg",
+ "PPC64 cache line size %u (type %u)\n",
+ (UInt)auxv->u.a_val, (UInt)auxv->a_type );
+ }
+# endif
+ break;
+
+# if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
+ case AT_IGNOREPPC:
+ break;
+# endif
+
+ case AT_SECURE:
+ /* If this is 1, then it means that this program is
+ running suid, and therefore the dynamic linker should
+ be careful about LD_PRELOAD, etc. However, since
+ stage1 (the thing the kernel actually execve's) should
+ never be SUID, and we need LD_PRELOAD to work for the
+ client, we set AT_SECURE to 0. */
+ auxv->u.a_val = 0;
+ break;
+
+ case AT_SYSINFO:
+# if !defined(VGP_ppc32_linux) && !defined(VGP_ppc64_linux)
+ case AT_SYSINFO_EHDR:
+# endif
+ /* Trash this, because we don't reproduce it */
+ auxv->a_type = AT_IGNORE;
+ break;
+
+ default:
+ /* stomp out anything we don't know about */
+ VG_(debugLog)(2, "initimg",
+ "stomping auxv entry %lld\n",
+ (ULong)auxv->a_type);
+ auxv->a_type = AT_IGNORE;
+ break;
+ }
+ }
+ *auxv = *orig_auxv;
+ vg_assert(auxv->a_type == AT_NULL);
+
+ vg_assert((strtab-stringbase) == stringsize);
+
+ /* client_SP is pointing at client's argc/argv */
+
+ if (0) VG_(printf)("startup SP = %#lx\n", client_SP);
+ return client_SP;
+}
+
+
+/* Allocate the client data segment. It is an expandable anonymous
+ mapping abutting a shrinkable reservation of size max_dseg_size.
+ The data segment starts at VG_(brk_base), which is page-aligned,
+ and runs up to VG_(brk_limit), which isn't. */
+
+static void setup_client_dataseg ( SizeT max_size )
+{
+ Bool ok;
+ SysRes sres;
+ Addr anon_start = VG_(brk_base);
+ SizeT anon_size = VKI_PAGE_SIZE;
+ Addr resvn_start = anon_start + anon_size;
+ SizeT resvn_size = max_size - anon_size;
+
+ vg_assert(VG_IS_PAGE_ALIGNED(anon_size));
+ vg_assert(VG_IS_PAGE_ALIGNED(resvn_size));
+ vg_assert(VG_IS_PAGE_ALIGNED(anon_start));
+ vg_assert(VG_IS_PAGE_ALIGNED(resvn_start));
+
+ /* Because there's been no brk activity yet: */
+ vg_assert(VG_(brk_base) == VG_(brk_limit));
+
+ /* Try to create the data seg and associated reservation where
+ VG_(brk_base) says. */
+ ok = VG_(am_create_reservation)(
+ resvn_start,
+ resvn_size,
+ SmLower,
+ anon_size
+ );
+
+ if (!ok) {
+ /* Hmm, that didn't work. Well, let aspacem suggest an address
+ it likes better, and try again with that. */
+ anon_start = VG_(am_get_advisory_client_simple)
+ ( 0/*floating*/, anon_size+resvn_size, &ok );
+ if (ok) {
+ resvn_start = anon_start + anon_size;
+ ok = VG_(am_create_reservation)(
+ resvn_start,
+ resvn_size,
+ SmLower,
+ anon_size
+ );
+ if (ok)
+ VG_(brk_base) = VG_(brk_limit) = anon_start;
+ }
+ /* that too might have failed, but if it has, we're hosed: there
+ is no Plan C. */
+ }
+ vg_assert(ok);
+
+ /* We make the data segment (heap) executable because LinuxThreads on
+ ppc32 creates trampolines in this area. Also, on x86/Linux the data
+ segment is RWX natively, at least according to /proc/self/maps.
+ Also, having a non-executable data seg would kill any program which
+ tried to create code in the data seg and then run it. */
+ sres = VG_(am_mmap_anon_fixed_client)(
+ anon_start,
+ anon_size,
+ VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC
+ );
+ vg_assert(!sres.isError);
+ vg_assert(sres.res == anon_start);
+}
+
+
+/*====================================================================*/
+/*=== TOP-LEVEL: VG_(setup_client_initial_image) ===*/
+/*====================================================================*/
+
+/* Create the client's initial memory image. */
+IIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo iicii )
+{
+ ExeInfo info;
+ HChar** env = NULL;
+
+ IIFinaliseImageInfo iifii;
+ VG_(memset)( &iifii, 0, sizeof(iifii) );
+
+ //--------------------------------------------------------------
+ // Load client executable, finding in $PATH if necessary
+ // p: get_helprequest_and_toolname() [for 'exec', 'need_help']
+ // p: layout_remaining_space [so there's space]
+ //--------------------------------------------------------------
+ VG_(debugLog)(1, "initimg", "Loading client\n");
+
+ if (VG_(args_the_exename) == NULL)
+ VG_(err_missing_prog)();
+
+ load_client(&info, &iifii.initial_client_IP, &iifii.initial_client_TOC);
+
+ //--------------------------------------------------------------
+ // Set up client's environment
+ // p: set-libdir [for VG_(libdir)]
+ // p: get_helprequest_and_toolname [for toolname]
+ //--------------------------------------------------------------
+ VG_(debugLog)(1, "initimg", "Setup client env\n");
+ env = setup_client_env(iicii.envp, iicii.toolname);
+
+ //--------------------------------------------------------------
+ // Setup client stack, eip, and VG_(client_arg[cv])
+ // p: load_client() [for 'info']
+ // p: fix_environment() [for 'env']
+ //--------------------------------------------------------------
+ {
+ /* When allocating space for the client stack on Linux, take
+ notice of the --main-stacksize value. This makes it possible
+ to run programs with very large (primary) stack requirements
+ simply by specifying --main-stacksize. */
+ /* Logic is as follows:
+ - by default, use the client's current stack rlimit
+ - if that exceeds 16M, clamp to 16M
+ - if a larger --main-stacksize value is specified, use that instead
+ - in all situations, the minimum allowed stack size is 1M
+ */
+ void* init_sp = iicii.argv - 1;
+ SizeT m1 = 1024 * 1024;
+ SizeT m16 = 16 * m1;
+ SizeT szB = (SizeT)VG_(client_rlimit_stack).rlim_cur;
+ if (szB < m1) szB = m1;
+ if (szB > m16) szB = m16;
+ if (VG_(clo_main_stacksize) > 0) szB = VG_(clo_main_stacksize);
+ if (szB < m1) szB = m1;
+ szB = VG_PGROUNDUP(szB);
+ VG_(debugLog)(1, "initimg",
+ "Setup client stack: size will be %ld\n", szB);
+
+ iifii.clstack_max_size = szB;
+
+ iifii.initial_client_SP
+ = setup_client_stack( init_sp, env,
+ &info, &iifii.client_auxv,
+ iicii.clstack_top, iifii.clstack_max_size );
+
+ VG_(free)(env);
+
+ VG_(debugLog)(2, "initimg",
+ "Client info: "
+ "initial_IP=%p initial_TOC=%p brk_base=%p\n",
+ (void*)(iifii.initial_client_IP),
+ (void*)(iifii.initial_client_TOC),
+ (void*)VG_(brk_base) );
+ VG_(debugLog)(2, "initimg",
+ "Client info: "
+ "initial_SP=%p max_stack_size=%ld\n",
+ (void*)(iifii.initial_client_SP),
+ (SizeT)iifii.clstack_max_size );
+ }
+
+ //--------------------------------------------------------------
+ // Setup client data (brk) segment. Initially a 1-page segment
+ // which abuts a shrinkable reservation.
+ // p: load_client() [for 'info' and hence VG_(brk_base)]
+ //--------------------------------------------------------------
+ {
+ SizeT m1 = 1024 * 1024;
+ SizeT m8 = 8 * m1;
+ SizeT dseg_max_size = (SizeT)VG_(client_rlimit_data).rlim_cur;
+ VG_(debugLog)(1, "initimg", "Setup client data (brk) segment\n");
+ if (dseg_max_size < m1) dseg_max_size = m1;
+ if (dseg_max_size > m8) dseg_max_size = m8;
+ dseg_max_size = VG_PGROUNDUP(dseg_max_size);
+
+ setup_client_dataseg( dseg_max_size );
+ }
+
+ return iifii;
+}
+
+
+/*====================================================================*/
+/*=== TOP-LEVEL: VG_(finalise_thread1state) ===*/
+/*====================================================================*/
+
+/* Just before starting the client, we may need to make final
+ adjustments to its initial image. Also we need to set up the VEX
+ guest state for thread 1 (the root thread) and copy in essential
+ starting values. This is handed the IIFinaliseImageInfo created by
+ VG_(ii_create_image).
+*/
+void VG_(ii_finalise_image)( IIFinaliseImageInfo iifii )
+{
+ ThreadArchState* arch = &VG_(threads)[1].arch;
+
+ /* On Linux we get client_{ip/sp/toc}, and start the client with
+ all other registers zeroed. */
+
+# if defined(VGP_x86_linux)
+ vg_assert(0 == sizeof(VexGuestX86State) % 16);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestX86_initialise(&arch->vex);
+
+ /* Zero out the shadow areas. */
+ VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestX86State));
+ VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestX86State));
+
+ /* Put essential stuff into the new state. */
+ arch->vex.guest_ESP = iifii.initial_client_SP;
+ arch->vex.guest_EIP = iifii.initial_client_IP;
+
+ /* initialise %cs, %ds and %ss to point at the operating systems
+ default code, data and stack segments */
+ asm volatile("movw %%cs, %0" : : "m" (arch->vex.guest_CS));
+ asm volatile("movw %%ds, %0" : : "m" (arch->vex.guest_DS));
+ asm volatile("movw %%ss, %0" : : "m" (arch->vex.guest_SS));
+
+# elif defined(VGP_amd64_linux)
+ vg_assert(0 == sizeof(VexGuestAMD64State) % 16);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestAMD64_initialise(&arch->vex);
+
+ /* Zero out the shadow areas. */
+ VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestAMD64State));
+ VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestAMD64State));
+
+ /* Put essential stuff into the new state. */
+ arch->vex.guest_RSP = iifii.initial_client_SP;
+ arch->vex.guest_RIP = iifii.initial_client_IP;
+
+# elif defined(VGP_ppc32_linux)
+ vg_assert(0 == sizeof(VexGuestPPC32State) % 16);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestPPC32_initialise(&arch->vex);
+
+ /* Zero out the shadow areas. */
+ VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestPPC32State));
+ VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestPPC32State));
+
+ /* Put essential stuff into the new state. */
+ arch->vex.guest_GPR1 = iifii.initial_client_SP;
+ arch->vex.guest_CIA = iifii.initial_client_IP;
+
+# elif defined(VGP_ppc64_linux)
+ vg_assert(0 == sizeof(VexGuestPPC64State) % 16);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestPPC64_initialise(&arch->vex);
+
+ /* Zero out the shadow areas. */
+ VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestPPC64State));
+ VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestPPC64State));
+
+ /* Put essential stuff into the new state. */
+ arch->vex.guest_GPR1 = iifii.initial_client_SP;
+ arch->vex.guest_GPR2 = iifii.initial_client_TOC;
+ arch->vex.guest_CIA = iifii.initial_client_IP;
+
+# else
+# error Unknown platform
+# endif
+
+ /* Tell the tool that we just wrote to the registers. */
+ VG_TRACK( post_reg_write, Vg_CoreStartup, /*tid*/1, /*offset*/0,
+ sizeof(VexGuestArchState));
+}
+
+
+/*--------------------------------------------------------------------*/
+/*--- initimg-linux.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_initimg/.svn/text-base/simple_huffman.c.svn-base b/coregrind/m_initimg/.svn/text-base/simple_huffman.c.svn-base
new file mode 100644
index 0000000..f9f3bb5
--- /dev/null
+++ b/coregrind/m_initimg/.svn/text-base/simple_huffman.c.svn-base
@@ -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;
+ }
+ }
+ }
+}
diff --git a/coregrind/m_initimg/initimg-aix5.c b/coregrind/m_initimg/initimg-aix5.c
new file mode 100644
index 0000000..24ca1bc
--- /dev/null
+++ b/coregrind/m_initimg/initimg-aix5.c
@@ -0,0 +1,545 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Startup: create initial process image on AIX5 ---*/
+/*--- initimg-aix5.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2006-2009 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.
+
+ Neither the names of the U.S. Department of Energy nor the
+ University of California nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without prior written permission.
+*/
+
+#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_xarray.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. --- */
+
+IIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo iicii )
+{
+ /* Set up an AIX5PreloadPage structure with the names of
+
+ $VALGRIND_LIB/vgpreload_core_PLATFORM.so
+ $VALGRIND_LIB/vgpreload_TOOL_PLATFORM.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* core = "core";
+ 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;
+
+ IIFinaliseImageInfo iifii;
+ VG_(memset)( &iifii, 0, sizeof(iifii) );
+
+ /* this can happen, if m_main decides to NULL it out */
+ if (VG_(args_the_exename) == NULL)
+ VG_(err_missing_prog)();
+
+ vg_assert( iicii.toolname );
+ pltool_len = VG_(strlen)( VG_(libdir) )
+ + 1 /*slash*/
+ + VG_(strlen)( vgpreload_ )
+ + VG_(strlen)( iicii.toolname )
+ + 1 /*dash*/
+ + VG_(strlen)(VG_PLATFORM)
+ + VG_(strlen)( _so )
+ + 1 /*NUL*/;
+ vg_assert(pltool_len > 0);
+ pltool_str = VG_(malloc)( "initimg-aix5.ici.1", pltool_len );
+ pltool_str[0] = 0;
+ VG_(strcat)( pltool_str, VG_(libdir) );
+ VG_(strcat)( pltool_str, "/" );
+ VG_(strcat)( pltool_str, vgpreload_ );
+ VG_(strcat)( pltool_str, iicii.toolname );
+ VG_(strcat)( pltool_str, "-" );
+ VG_(strcat)( pltool_str, VG_PLATFORM );
+ 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)( vgpreload_ )
+ + VG_(strlen)( core )
+ + 1 /*dash*/
+ + VG_(strlen)(VG_PLATFORM)
+ + VG_(strlen)(_so)
+ + 1 /*NUL*/;
+ vg_assert(plcore_len > 0);
+ plcore_str = VG_(malloc)( "initimg-aix5.ici.2", plcore_len );
+ plcore_str[0] = 0;
+ VG_(strcat)( plcore_str, VG_(libdir) );
+ VG_(strcat)( plcore_str, "/" );
+ VG_(strcat)( plcore_str, vgpreload_ );
+ VG_(strcat)( plcore_str, core );
+ VG_(strcat)( plcore_str, "-" );
+ VG_(strcat)( plcore_str, VG_PLATFORM );
+ VG_(strcat)( plcore_str, _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)( "initimg-aix5.ici.3", 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-<platform>.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;
+
+ iifii.preloadpage = pp;
+ iifii.intregs37 = iicii.intregs37;
+ iifii.initial_client_SP = iicii.intregs37[1]; /* r1 */
+ iifii.compressed_page = VG_PGROUNDDN((Addr)iicii.bootblock);
+ iifii.adler32_exp = iicii.adler32_exp;
+ iifii.clstack_max_size = 0; /* we don't know yet */
+ return iifii;
+}
+
+
+/* --- 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;
+}
+
+/* Just before starting the client, we may need to make final
+ adjustments to its initial image. Also we need to set up the VEX
+ guest state for thread 1 (the root thread) and copy in essential
+ starting values. This is handed the IIFinaliseImageInfo created by
+ VG_(ii_create_image).
+*/
+void VG_(ii_finalise_image)( IIFinaliseImageInfo iifii )
+{
+ 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. */
+
+ ThreadArchState* arch = &VG_(threads)[1].arch;
+
+# if defined(VGP_ppc32_aix5)
+
+ vg_assert(0 == sizeof(VexGuestPPC32State) % 16);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestPPC32_initialise(&arch->vex);
+
+ /* Zero out the shadow areas. */
+ VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestPPC32State));
+ VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestPPC32State));
+
+# else /* defined(VGP_ppc64_aix5) */
+
+ vg_assert(0 == sizeof(VexGuestPPC64State) % 16);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestPPC64_initialise(&arch->vex);
+
+ /* Zero out the shadow areas. */
+ VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestPPC64State));
+ VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestPPC64State));
+
+# endif
+
+ /* iifii.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)iifii.intregs37[0];
+ arch->vex.guest_GPR1 = (UWord)iifii.intregs37[1];
+ arch->vex.guest_GPR2 = (UWord)iifii.intregs37[2];
+ arch->vex.guest_GPR3 = (UWord)iifii.intregs37[3];
+ arch->vex.guest_GPR4 = (UWord)iifii.intregs37[4];
+ arch->vex.guest_GPR5 = (UWord)iifii.intregs37[5];
+ arch->vex.guest_GPR6 = (UWord)iifii.intregs37[6];
+ arch->vex.guest_GPR7 = (UWord)iifii.intregs37[7];
+ arch->vex.guest_GPR8 = (UWord)iifii.intregs37[8];
+ arch->vex.guest_GPR9 = (UWord)iifii.intregs37[9];
+ arch->vex.guest_GPR10 = (UWord)iifii.intregs37[10];
+ arch->vex.guest_GPR11 = (UWord)iifii.intregs37[11];
+ arch->vex.guest_GPR12 = (UWord)iifii.intregs37[12];
+ arch->vex.guest_GPR13 = (UWord)iifii.intregs37[13];
+ arch->vex.guest_GPR14 = (UWord)iifii.intregs37[14];
+ arch->vex.guest_GPR15 = (UWord)iifii.intregs37[15];
+ arch->vex.guest_GPR16 = (UWord)iifii.intregs37[16];
+ arch->vex.guest_GPR17 = (UWord)iifii.intregs37[17];
+ arch->vex.guest_GPR18 = (UWord)iifii.intregs37[18];
+ arch->vex.guest_GPR19 = (UWord)iifii.intregs37[19];
+ arch->vex.guest_GPR20 = (UWord)iifii.intregs37[20];
+ arch->vex.guest_GPR21 = (UWord)iifii.intregs37[21];
+ arch->vex.guest_GPR22 = (UWord)iifii.intregs37[22];
+ arch->vex.guest_GPR23 = (UWord)iifii.intregs37[23];
+ arch->vex.guest_GPR24 = (UWord)iifii.intregs37[24];
+ arch->vex.guest_GPR25 = (UWord)iifii.intregs37[25];
+ arch->vex.guest_GPR26 = (UWord)iifii.intregs37[26];
+ arch->vex.guest_GPR27 = (UWord)iifii.intregs37[27];
+ arch->vex.guest_GPR28 = (UWord)iifii.intregs37[28];
+ arch->vex.guest_GPR29 = (UWord)iifii.intregs37[29];
+ arch->vex.guest_GPR30 = (UWord)iifii.intregs37[30];
+ arch->vex.guest_GPR31 = (UWord)iifii.intregs37[31];
+
+ arch->vex.guest_CIA = (UWord)iifii.intregs37[32+0];
+ arch->vex.guest_LR = (UWord)iifii.intregs37[32+2];
+ arch->vex.guest_CTR = (UWord)iifii.intregs37[32+3];
+
+# if defined(VGP_ppc32_aix5)
+
+ LibVEX_GuestPPC32_put_CR( (UWord)iifii.intregs37[32+1], &arch->vex );
+ LibVEX_GuestPPC32_put_XER( (UWord)iifii.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)iifii.intregs37[32+1], &arch->vex );
+ LibVEX_GuestPPC64_put_XER( (UWord)iifii.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)
+
+ { UWord n_vargs = VG_(sizeXA)( VG_(args_for_valgrind) );
+ vg_assert(arch->vex.guest_GPR3 >= 1 + n_vargs);
+ arch->vex.guest_GPR3 -= (1 + n_vargs);
+ arch->vex.guest_GPR4 += sizeof(UWord) * (1 + n_vargs);
+ }
+
+# else /* defined(VGP_ppc64_aix5) */
+
+ { UWord n_vargs = VG_(sizeXA)( VG_(args_for_valgrind) );
+ vg_assert(arch->vex.guest_GPR14 >= 1 + n_vargs);
+ arch->vex.guest_GPR14 -= (1 + n_vargs);
+ arch->vex.guest_GPR15 += sizeof(UWord) * (1 + n_vargs);
+ }
+
+# 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{32,64}_aix5_do_preloads_then_start_client),
+ passing it iifii.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 */
+ iifii.preloadpage->r2 = (ULong)arch->vex.guest_GPR2;
+ iifii.preloadpage->r3 = (ULong)arch->vex.guest_GPR3;
+ iifii.preloadpage->r4 = (ULong)arch->vex.guest_GPR4;
+ iifii.preloadpage->r5 = (ULong)arch->vex.guest_GPR5;
+ iifii.preloadpage->r6 = (ULong)arch->vex.guest_GPR6;
+ iifii.preloadpage->r7 = (ULong)arch->vex.guest_GPR7;
+ iifii.preloadpage->r8 = (ULong)arch->vex.guest_GPR8;
+ iifii.preloadpage->r9 = (ULong)arch->vex.guest_GPR9;
+ iifii.preloadpage->r10 = (ULong)arch->vex.guest_GPR10;
+ iifii.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)iifii.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 iifii.intregs37. So we have
+ to wait till this point, at which we're done with iifii.intregs37
+ (to be precise, with what it points at). */
+ VG_(debugLog)(1, "initimg", "decompressing page at %p\n",
+ (void*)iifii.compressed_page);
+ vg_assert(VG_IS_PAGE_ALIGNED(iifii.compressed_page));
+
+ Huffman_Uncompress( (void*)iifii.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, iifii.adler32_exp );
+
+ VG_(memcpy)((void*)iifii.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/vgpreload_core-ppc32-aix5.so
+
+ in which case
+
+ $ execerror xyzzy \
+ "(ld 3 1 __libc_freeres /foo/bar/vgpreload_core-ppc32-aix5.so"
+
+ gets you
+
+ Could not load program xyzzy:
+ rtld: 0712-001 Symbol __libc_freeres was referenced
+ from module /foo/bar/vgpreload_core-ppc32-aix5.so(),
+ but a runtime definition
+ of the symbol was not found.
+*/
+
+/*--------------------------------------------------------------------*/
+/*--- initimg-aix5.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_initimg/initimg-linux.c b/coregrind/m_initimg/initimg-linux.c
new file mode 100644
index 0000000..e80dc22
--- /dev/null
+++ b/coregrind/m_initimg/initimg-linux.c
@@ -0,0 +1,1074 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Startup: create initial process image on Linux ---*/
+/*--- initimg-linux.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2009 Julian Seward
+ jseward@acm.org
+
+ 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_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_xarray.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_syscall.h"
+#include "pub_core_tooliface.h" /* VG_TRACK */
+#include "pub_core_threadstate.h" /* ThreadArchState */
+#include "pub_core_initimg.h" /* self */
+
+/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
+#define _GNU_SOURCE
+#define _FILE_OFFSET_BITS 64
+/* This is for ELF types etc, and also the AT_ constants. */
+#include <elf.h>
+/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
+
+
+/*====================================================================*/
+/*=== Find executable ===*/
+/*====================================================================*/
+
+/* Scan a colon-separated list, and call a function on each element.
+ The string must be mutable, because we insert a temporary '\0', but
+ the string will end up unmodified. (*func) should return True if it
+ doesn't need to see any more.
+
+ This routine will return True if (*func) returns True and False if
+ it reaches the end of the list without that happening.
+*/
+static Bool scan_colsep(char *colsep, Bool (*func)(const char *))
+{
+ char *cp, *entry;
+ int end;
+
+ if (colsep == NULL ||
+ *colsep == '\0')
+ return False;
+
+ entry = cp = colsep;
+
+ do {
+ end = (*cp == '\0');
+
+ if (*cp == ':' || *cp == '\0') {
+ char save = *cp;
+
+ *cp = '\0';
+ if ((*func)(entry)) {
+ *cp = save;
+ return True;
+ }
+ *cp = save;
+ entry = cp+1;
+ }
+ cp++;
+ } while(!end);
+
+ return False;
+}
+
+/* Need a static copy because can't use dynamic mem allocation yet */
+static HChar executable_name_in [VKI_PATH_MAX];
+static HChar executable_name_out[VKI_PATH_MAX];
+
+static Bool match_executable(const char *entry)
+{
+ HChar buf[VG_(strlen)(entry) + VG_(strlen)(executable_name_in) + 3];
+
+ /* empty PATH element means '.' */
+ if (*entry == '\0')
+ entry = ".";
+
+ VG_(snprintf)(buf, sizeof(buf), "%s/%s", entry, executable_name_in);
+
+ // Don't match directories
+ if (VG_(is_dir)(buf))
+ return False;
+
+ // If we match an executable, we choose that immediately. If we find a
+ // matching non-executable we remember it but keep looking for an
+ // matching executable later in the path.
+ if (VG_(access)(buf, True/*r*/, False/*w*/, True/*x*/) == 0) {
+ VG_(strncpy)( executable_name_out, buf, VKI_PATH_MAX-1 );
+ executable_name_out[VKI_PATH_MAX-1] = 0;
+ return True; // Stop looking
+ } else if (VG_(access)(buf, True/*r*/, False/*w*/, False/*x*/) == 0
+ && VG_STREQ(executable_name_out, ""))
+ {
+ VG_(strncpy)( executable_name_out, buf, VKI_PATH_MAX-1 );
+ executable_name_out[VKI_PATH_MAX-1] = 0;
+ return False; // Keep looking
+ } else {
+ return False; // Keep looking
+ }
+}
+
+// Returns NULL if it wasn't found.
+static HChar* find_executable ( HChar* exec )
+{
+ vg_assert(NULL != exec);
+ if (VG_(strchr)(exec, '/')) {
+ // Has a '/' - use the name as is
+ VG_(strncpy)( executable_name_out, exec, VKI_PATH_MAX-1 );
+ } else {
+ // No '/' - we need to search the path
+ HChar* path;
+ VG_(strncpy)( executable_name_in, exec, VKI_PATH_MAX-1 );
+ VG_(memset) ( executable_name_out, 0, VKI_PATH_MAX );
+ path = VG_(getenv)("PATH");
+ scan_colsep(path, match_executable);
+ }
+ return VG_STREQ(executable_name_out, "") ? NULL : executable_name_out;
+}
+
+
+/*====================================================================*/
+/*=== Loading the client ===*/
+/*====================================================================*/
+
+/* Load the client whose name is VG_(argv_the_exename). */
+
+static void load_client ( /*OUT*/ExeInfo* info,
+ /*OUT*/Addr* client_ip,
+ /*OUT*/Addr* client_toc)
+{
+ HChar* exe_name;
+ Int ret;
+ SysRes res;
+
+ vg_assert( VG_(args_the_exename) != NULL);
+ exe_name = find_executable( VG_(args_the_exename) );
+
+ if (!exe_name) {
+ VG_(printf)("valgrind: %s: command not found\n", VG_(args_the_exename));
+ VG_(exit)(127); // 127 is Posix NOTFOUND
+ }
+
+ VG_(memset)(info, 0, sizeof(*info));
+ ret = VG_(do_exec)(exe_name, info);
+ if (ret < 0) {
+ VG_(printf)("valgrind: could not execute '%s'\n", exe_name);
+ VG_(exit)(1);
+ }
+
+ // The client was successfully loaded! Continue.
+
+ /* Get hold of a file descriptor which refers to the client
+ 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.res;
+
+ /* Copy necessary bits of 'info' that were filled in */
+ *client_ip = info->init_ip;
+ *client_toc = info->init_toc;
+ VG_(brk_base) = VG_(brk_limit) = VG_PGROUNDUP(info->brkbase);
+}
+
+
+/*====================================================================*/
+/*=== Setting up the client's environment ===*/
+/*====================================================================*/
+
+/* Prepare the client's environment. This is basically a copy of our
+ environment, except:
+
+ LD_PRELOAD=$VALGRIND_LIB/vgpreload_core-PLATFORM.so:
+ ($VALGRIND_LIB/vgpreload_TOOL-PLATFORM.so:)?
+ $LD_PRELOAD
+
+ If this is missing, then it is added.
+
+ Also, remove any binding for VALGRIND_LAUNCHER=. The client should
+ not be able to see this.
+
+ If this needs to handle any more variables it should be hacked
+ into something table driven. The copy is VG_(malloc)'d space.
+*/
+static HChar** setup_client_env ( HChar** origenv, const HChar* toolname)
+{
+ HChar* preload_core = "vgpreload_core";
+ HChar* ld_preload = "LD_PRELOAD=";
+ HChar* v_launcher = VALGRIND_LAUNCHER "=";
+ Int ld_preload_len = VG_(strlen)( ld_preload );
+ Int v_launcher_len = VG_(strlen)( v_launcher );
+ Bool ld_preload_done = False;
+ Int vglib_len = VG_(strlen)(VG_(libdir));
+
+ HChar** cpp;
+ HChar** ret;
+ HChar* preload_tool_path;
+ Int envc, i;
+
+ /* Alloc space for the vgpreload_core.so path and vgpreload_<tool>.so
+ paths. We might not need the space for vgpreload_<tool>.so, but it
+ doesn't hurt to over-allocate briefly. The 16s are just cautious
+ slop. */
+ Int preload_core_path_len = vglib_len + sizeof(preload_core)
+ + sizeof(VG_PLATFORM) + 16;
+ Int preload_tool_path_len = vglib_len + VG_(strlen)(toolname)
+ + sizeof(VG_PLATFORM) + 16;
+ Int preload_string_len = preload_core_path_len + preload_tool_path_len;
+ HChar* preload_string = VG_(malloc)("initimg-linux.sce.1",
+ preload_string_len);
+ vg_assert(origenv);
+ vg_assert(toolname);
+ vg_assert(preload_string);
+
+ /* Determine if there's a vgpreload_<tool>_<platform>.so file, and setup
+ preload_string. */
+ preload_tool_path = VG_(malloc)("initimg-linux.sce.2", preload_tool_path_len);
+ vg_assert(preload_tool_path);
+ VG_(snprintf)(preload_tool_path, preload_tool_path_len,
+ "%s/vgpreload_%s-%s.so", VG_(libdir), toolname, VG_PLATFORM);
+ if (VG_(access)(preload_tool_path, True/*r*/, False/*w*/, False/*x*/) == 0) {
+ VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so:%s",
+ VG_(libdir), preload_core, VG_PLATFORM, preload_tool_path);
+ } else {
+ VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so",
+ VG_(libdir), preload_core, VG_PLATFORM);
+ }
+ VG_(free)(preload_tool_path);
+
+ VG_(debugLog)(2, "initimg", "preload_string:\n");
+ VG_(debugLog)(2, "initimg", " \"%s\"\n", preload_string);
+
+ /* Count the original size of the env */
+ envc = 0;
+ for (cpp = origenv; cpp && *cpp; cpp++)
+ envc++;
+
+ /* Allocate a new space */
+ ret = VG_(malloc) ("initimg-linux.sce.3",
+ sizeof(HChar *) * (envc+1+1)); /* 1 new entry + NULL */
+ vg_assert(ret);
+
+ /* copy it over */
+ for (cpp = ret; *origenv; )
+ *cpp++ = *origenv++;
+ *cpp = NULL;
+
+ vg_assert(envc == (cpp - ret));
+
+ /* Walk over the new environment, mashing as we go */
+ for (cpp = ret; cpp && *cpp; cpp++) {
+ if (VG_(memcmp)(*cpp, ld_preload, ld_preload_len) == 0) {
+ Int len = VG_(strlen)(*cpp) + preload_string_len;
+ HChar *cp = VG_(malloc)("initimg-linux.sce.4", len);
+ vg_assert(cp);
+
+ VG_(snprintf)(cp, len, "%s%s:%s",
+ ld_preload, preload_string, (*cpp)+ld_preload_len);
+
+ *cpp = cp;
+
+ ld_preload_done = True;
+ }
+ }
+
+ /* Add the missing bits */
+ if (!ld_preload_done) {
+ Int len = ld_preload_len + preload_string_len;
+ HChar *cp = VG_(malloc) ("initimg-linux.sce.5", len);
+ vg_assert(cp);
+
+ VG_(snprintf)(cp, len, "%s%s", ld_preload, preload_string);
+
+ ret[envc++] = cp;
+ }
+
+ /* ret[0 .. envc-1] is live now. */
+ /* Find and remove a binding for VALGRIND_LAUNCHER. */
+ for (i = 0; i < envc; i++)
+ if (0 == VG_(memcmp(ret[i], v_launcher, v_launcher_len)))
+ break;
+
+ if (i < envc) {
+ for (; i < envc-1; i++)
+ ret[i] = ret[i+1];
+ envc--;
+ }
+
+ VG_(free)(preload_string);
+ ret[envc] = NULL;
+
+ return ret;
+}
+
+
+/*====================================================================*/
+/*=== Setting up the client's stack ===*/
+/*====================================================================*/
+
+#ifndef AT_DCACHEBSIZE
+#define AT_DCACHEBSIZE 19
+#endif /* AT_DCACHEBSIZE */
+
+#ifndef AT_ICACHEBSIZE
+#define AT_ICACHEBSIZE 20
+#endif /* AT_ICACHEBSIZE */
+
+#ifndef AT_UCACHEBSIZE
+#define AT_UCACHEBSIZE 21
+#endif /* AT_UCACHEBSIZE */
+
+#ifndef AT_SYSINFO
+#define AT_SYSINFO 32
+#endif /* AT_SYSINFO */
+
+#ifndef AT_SYSINFO_EHDR
+#define AT_SYSINFO_EHDR 33
+#endif /* AT_SYSINFO_EHDR */
+
+#ifndef AT_SECURE
+#define AT_SECURE 23 /* secure mode boolean */
+#endif /* AT_SECURE */
+
+/* Add a string onto the string table, and return its address */
+static char *copy_str(char **tab, const char *str)
+{
+ char *cp = *tab;
+ char *orig = cp;
+
+ while(*str)
+ *cp++ = *str++;
+ *cp++ = '\0';
+
+ if (0)
+ VG_(printf)("copied %p \"%s\" len %lld\n", orig, orig, (Long)(cp-orig));
+
+ *tab = cp;
+
+ return orig;
+}
+
+
+/* ----------------------------------------------------------------
+
+ This sets up the client's initial stack, containing the args,
+ environment and aux vector.
+
+ The format of the stack is:
+
+ higher address +-----------------+ <- clstack_end
+ | |
+ : string table :
+ | |
+ +-----------------+
+ | AT_NULL |
+ - -
+ | auxv |
+ +-----------------+
+ | NULL |
+ - -
+ | envp |
+ +-----------------+
+ | NULL |
+ - -
+ | argv |
+ +-----------------+
+ | argc |
+ lower address +-----------------+ <- sp
+ | undefined |
+ : :
+
+ Allocate and create the initial client stack. It is allocated down
+ from clstack_end, which was previously determined by the address
+ space manager. The returned value is the SP value for the client.
+
+ The client's auxv is created by copying and modifying our own one.
+ As a side effect of scanning our own auxv, some important bits of
+ info are collected:
+
+ VG_(cache_line_size_ppc32) // ppc32 only -- cache line size
+ VG_(have_altivec_ppc32) // ppc32 only -- is Altivec supported?
+
+ ---------------------------------------------------------------- */
+
+struct auxv
+{
+ Word a_type;
+ union {
+ void *a_ptr;
+ Word a_val;
+ } u;
+};
+
+static
+struct auxv *find_auxv(UWord* sp)
+{
+ sp++; // skip argc (Nb: is word-sized, not int-sized!)
+
+ while (*sp != 0) // skip argv
+ sp++;
+ sp++;
+
+ while (*sp != 0) // skip env
+ sp++;
+ sp++;
+
+#if defined(VGA_ppc32) || defined(VGA_ppc64)
+# if defined AT_IGNOREPPC
+ while (*sp == AT_IGNOREPPC) // skip AT_IGNOREPPC entries
+ sp += 2;
+# endif
+#endif
+
+ return (struct auxv *)sp;
+}
+
+static
+Addr setup_client_stack( void* init_sp,
+ char** orig_envp,
+ const ExeInfo* info,
+ UInt** client_auxv,
+ Addr clstack_end,
+ SizeT clstack_max_size )
+{
+ SysRes res;
+ char **cpp;
+ char *strtab; /* string table */
+ char *stringbase;
+ Addr *ptr;
+ struct auxv *auxv;
+ const struct auxv *orig_auxv;
+ const struct auxv *cauxv;
+ unsigned stringsize; /* total size of strings in bytes */
+ unsigned auxsize; /* total size of auxv in bytes */
+ Int argc; /* total argc */
+ Int envc; /* total number of env vars */
+ unsigned stacksize; /* total client stack size */
+ Addr client_SP; /* client stack base (initial SP) */
+ Addr clstack_start;
+ Int i;
+ Bool have_exename;
+
+ vg_assert(VG_IS_PAGE_ALIGNED(clstack_end+1));
+ vg_assert( VG_(args_for_client) );
+
+ /* use our own auxv as a prototype */
+ orig_auxv = find_auxv(init_sp);
+
+ /* ==================== compute sizes ==================== */
+
+ /* first of all, work out how big the client stack will be */
+ stringsize = 0;
+ have_exename = VG_(args_the_exename) != NULL;
+
+ /* paste on the extra args if the loader needs them (ie, the #!
+ interpreter and its argument) */
+ argc = 0;
+ if (info->interp_name != NULL) {
+ argc++;
+ stringsize += VG_(strlen)(info->interp_name) + 1;
+ }
+ if (info->interp_args != NULL) {
+ argc++;
+ stringsize += VG_(strlen)(info->interp_args) + 1;
+ }
+
+ /* now scan the args we're given... */
+ if (have_exename)
+ stringsize += VG_(strlen)( VG_(args_the_exename) ) + 1;
+
+ for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
+ argc++;
+ stringsize += VG_(strlen)( * (HChar**)
+ VG_(indexXA)( VG_(args_for_client), i ))
+ + 1;
+ }
+
+ /* ...and the environment */
+ envc = 0;
+ for (cpp = orig_envp; cpp && *cpp; cpp++) {
+ envc++;
+ stringsize += VG_(strlen)(*cpp) + 1;
+ }
+
+ /* now, how big is the auxv? */
+ auxsize = sizeof(*auxv); /* there's always at least one entry: AT_NULL */
+ for (cauxv = orig_auxv; cauxv->a_type != AT_NULL; cauxv++) {
+ if (cauxv->a_type == AT_PLATFORM)
+ stringsize += VG_(strlen)(cauxv->u.a_ptr) + 1;
+ auxsize += sizeof(*cauxv);
+ }
+
+# if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
+ auxsize += 2 * sizeof(*cauxv);
+# endif
+
+ /* OK, now we know how big the client stack is */
+ stacksize =
+ sizeof(Word) + /* argc */
+ (have_exename ? sizeof(char **) : 0) + /* argc[0] == exename */
+ sizeof(char **)*argc + /* argv */
+ sizeof(char **) + /* terminal NULL */
+ sizeof(char **)*envc + /* envp */
+ sizeof(char **) + /* terminal NULL */
+ auxsize + /* auxv */
+ VG_ROUNDUP(stringsize, sizeof(Word)); /* strings (aligned) */
+
+ if (0) VG_(printf)("stacksize = %d\n", stacksize);
+
+ /* client_SP is the client's stack pointer */
+ client_SP = clstack_end - stacksize;
+ client_SP = VG_ROUNDDN(client_SP, 16); /* make stack 16 byte aligned */
+
+ /* base of the string table (aligned) */
+ stringbase = strtab = (char *)clstack_end
+ - VG_ROUNDUP(stringsize, sizeof(int));
+
+ clstack_start = VG_PGROUNDDN(client_SP);
+
+ /* The max stack size */
+ clstack_max_size = VG_PGROUNDUP(clstack_max_size);
+
+ /* Record stack extent -- needed for stack-change code. */
+ VG_(clstk_base) = clstack_start;
+ VG_(clstk_end) = clstack_end;
+
+ if (0)
+ VG_(printf)("stringsize=%d auxsize=%d stacksize=%d maxsize=0x%x\n"
+ "clstack_start %p\n"
+ "clstack_end %p\n",
+ stringsize, auxsize, stacksize, (Int)clstack_max_size,
+ (void*)clstack_start, (void*)clstack_end);
+
+ /* ==================== allocate space ==================== */
+
+ { SizeT anon_size = clstack_end - clstack_start + 1;
+ SizeT resvn_size = clstack_max_size - anon_size;
+ Addr anon_start = clstack_start;
+ Addr resvn_start = anon_start - resvn_size;
+ SizeT inner_HACK = 0;
+ Bool ok;
+
+ /* So far we've only accounted for space requirements down to the
+ stack pointer. If this target's ABI requires a redzone below
+ the stack pointer, we need to allocate an extra page, to
+ handle the worst case in which the stack pointer is almost at
+ the bottom of a page, and so there is insufficient room left
+ over to put the redzone in. In this case the simple thing to
+ do is allocate an extra page, by shrinking the reservation by
+ one page and growing the anonymous area by a corresponding
+ page. */
+ vg_assert(VG_STACK_REDZONE_SZB >= 0);
+ vg_assert(VG_STACK_REDZONE_SZB < VKI_PAGE_SIZE);
+ if (VG_STACK_REDZONE_SZB > 0) {
+ vg_assert(resvn_size > VKI_PAGE_SIZE);
+ resvn_size -= VKI_PAGE_SIZE;
+ anon_start -= VKI_PAGE_SIZE;
+ anon_size += VKI_PAGE_SIZE;
+ }
+
+ vg_assert(VG_IS_PAGE_ALIGNED(anon_size));
+ vg_assert(VG_IS_PAGE_ALIGNED(resvn_size));
+ vg_assert(VG_IS_PAGE_ALIGNED(anon_start));
+ vg_assert(VG_IS_PAGE_ALIGNED(resvn_start));
+ vg_assert(resvn_start == clstack_end + 1 - clstack_max_size);
+
+# ifdef ENABLE_INNER
+ inner_HACK = 1024*1024; // create 1M non-fault-extending stack
+# endif
+
+ if (0)
+ VG_(printf)("%#lx 0x%lx %#lx 0x%lx\n",
+ resvn_start, resvn_size, anon_start, anon_size);
+
+ /* Create a shrinkable reservation followed by an anonymous
+ segment. Together these constitute a growdown stack. */
+ res = VG_(mk_SysRes_Error)(0);
+ ok = VG_(am_create_reservation)(
+ resvn_start,
+ resvn_size -inner_HACK,
+ SmUpper,
+ anon_size +inner_HACK
+ );
+ if (ok) {
+ /* allocate a stack - mmap enough space for the stack */
+ res = VG_(am_mmap_anon_fixed_client)(
+ anon_start -inner_HACK,
+ anon_size +inner_HACK,
+ VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC
+ );
+ }
+ if ((!ok) || res.isError) {
+ /* Allocation of the stack failed. We have to stop. */
+ VG_(printf)("valgrind: "
+ "I failed to allocate space for the application's stack.\n");
+ VG_(printf)("valgrind: "
+ "This may be the result of a very large --main-stacksize=\n");
+ VG_(printf)("valgrind: setting. Cannot continue. Sorry.\n\n");
+ VG_(exit)(0);
+ }
+
+ vg_assert(ok);
+ vg_assert(!res.isError);
+ }
+
+ /* ==================== create client stack ==================== */
+
+ ptr = (Addr*)client_SP;
+
+ /* --- client argc --- */
+ *ptr++ = argc + (have_exename ? 1 : 0);
+
+ /* --- client argv --- */
+ if (info->interp_name) {
+ *ptr++ = (Addr)copy_str(&strtab, info->interp_name);
+ VG_(free)(info->interp_name);
+ }
+ if (info->interp_args) {
+ *ptr++ = (Addr)copy_str(&strtab, info->interp_args);
+ VG_(free)(info->interp_args);
+ }
+
+ if (have_exename)
+ *ptr++ = (Addr)copy_str(&strtab, VG_(args_the_exename));
+
+ for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
+ *ptr++ = (Addr)copy_str(
+ &strtab,
+ * (HChar**) VG_(indexXA)( VG_(args_for_client), i )
+ );
+ }
+ *ptr++ = 0;
+
+ /* --- envp --- */
+ VG_(client_envp) = (Char **)ptr;
+ for (cpp = orig_envp; cpp && *cpp; ptr++, cpp++)
+ *ptr = (Addr)copy_str(&strtab, *cpp);
+ *ptr++ = 0;
+
+ /* --- auxv --- */
+ auxv = (struct auxv *)ptr;
+ *client_auxv = (UInt *)auxv;
+
+# if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
+ auxv[0].a_type = AT_IGNOREPPC;
+ auxv[0].u.a_val = AT_IGNOREPPC;
+ auxv[1].a_type = AT_IGNOREPPC;
+ auxv[1].u.a_val = AT_IGNOREPPC;
+ auxv += 2;
+# endif
+
+ for (; orig_auxv->a_type != AT_NULL; auxv++, orig_auxv++) {
+
+ /* copy the entry... */
+ *auxv = *orig_auxv;
+
+ /* ...and fix up / examine the copy */
+ switch(auxv->a_type) {
+
+ case AT_IGNORE:
+ case AT_PHENT:
+ case AT_PAGESZ:
+ case AT_FLAGS:
+ case AT_NOTELF:
+ case AT_UID:
+ case AT_EUID:
+ case AT_GID:
+ case AT_EGID:
+ case AT_CLKTCK:
+ case AT_FPUCW:
+ /* All these are pointerless, so we don't need to do
+ anything about them. */
+ break;
+
+ case AT_PHDR:
+ if (info->phdr == 0)
+ auxv->a_type = AT_IGNORE;
+ else
+ auxv->u.a_val = info->phdr;
+ break;
+
+ case AT_PHNUM:
+ if (info->phdr == 0)
+ auxv->a_type = AT_IGNORE;
+ else
+ auxv->u.a_val = info->phnum;
+ break;
+
+ case AT_BASE:
+ auxv->u.a_val = info->interp_base;
+ break;
+
+ case AT_PLATFORM:
+ /* points to a platform description string */
+ auxv->u.a_ptr = copy_str(&strtab, orig_auxv->u.a_ptr);
+ break;
+
+ case AT_ENTRY:
+ auxv->u.a_val = info->entry;
+ break;
+
+ case AT_HWCAP:
+ break;
+
+ case AT_DCACHEBSIZE:
+ case AT_ICACHEBSIZE:
+ case AT_UCACHEBSIZE:
+# if defined(VGP_ppc32_linux)
+ /* acquire cache info */
+ if (auxv->u.a_val > 0) {
+ VG_(machine_ppc32_set_clszB)( auxv->u.a_val );
+ VG_(debugLog)(2, "initimg",
+ "PPC32 cache line size %u (type %u)\n",
+ (UInt)auxv->u.a_val, (UInt)auxv->a_type );
+ }
+# elif defined(VGP_ppc64_linux)
+ /* acquire cache info */
+ if (auxv->u.a_val > 0) {
+ VG_(machine_ppc64_set_clszB)( auxv->u.a_val );
+ VG_(debugLog)(2, "initimg",
+ "PPC64 cache line size %u (type %u)\n",
+ (UInt)auxv->u.a_val, (UInt)auxv->a_type );
+ }
+# endif
+ break;
+
+# if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
+ case AT_IGNOREPPC:
+ break;
+# endif
+
+ case AT_SECURE:
+ /* If this is 1, then it means that this program is
+ running suid, and therefore the dynamic linker should
+ be careful about LD_PRELOAD, etc. However, since
+ stage1 (the thing the kernel actually execve's) should
+ never be SUID, and we need LD_PRELOAD to work for the
+ client, we set AT_SECURE to 0. */
+ auxv->u.a_val = 0;
+ break;
+
+ case AT_SYSINFO:
+# if !defined(VGP_ppc32_linux) && !defined(VGP_ppc64_linux)
+ case AT_SYSINFO_EHDR:
+# endif
+ /* Trash this, because we don't reproduce it */
+ auxv->a_type = AT_IGNORE;
+ break;
+
+ default:
+ /* stomp out anything we don't know about */
+ VG_(debugLog)(2, "initimg",
+ "stomping auxv entry %lld\n",
+ (ULong)auxv->a_type);
+ auxv->a_type = AT_IGNORE;
+ break;
+ }
+ }
+ *auxv = *orig_auxv;
+ vg_assert(auxv->a_type == AT_NULL);
+
+ vg_assert((strtab-stringbase) == stringsize);
+
+ /* client_SP is pointing at client's argc/argv */
+
+ if (0) VG_(printf)("startup SP = %#lx\n", client_SP);
+ return client_SP;
+}
+
+
+/* Allocate the client data segment. It is an expandable anonymous
+ mapping abutting a shrinkable reservation of size max_dseg_size.
+ The data segment starts at VG_(brk_base), which is page-aligned,
+ and runs up to VG_(brk_limit), which isn't. */
+
+static void setup_client_dataseg ( SizeT max_size )
+{
+ Bool ok;
+ SysRes sres;
+ Addr anon_start = VG_(brk_base);
+ SizeT anon_size = VKI_PAGE_SIZE;
+ Addr resvn_start = anon_start + anon_size;
+ SizeT resvn_size = max_size - anon_size;
+
+ vg_assert(VG_IS_PAGE_ALIGNED(anon_size));
+ vg_assert(VG_IS_PAGE_ALIGNED(resvn_size));
+ vg_assert(VG_IS_PAGE_ALIGNED(anon_start));
+ vg_assert(VG_IS_PAGE_ALIGNED(resvn_start));
+
+ /* Because there's been no brk activity yet: */
+ vg_assert(VG_(brk_base) == VG_(brk_limit));
+
+ /* Try to create the data seg and associated reservation where
+ VG_(brk_base) says. */
+ ok = VG_(am_create_reservation)(
+ resvn_start,
+ resvn_size,
+ SmLower,
+ anon_size
+ );
+
+ if (!ok) {
+ /* Hmm, that didn't work. Well, let aspacem suggest an address
+ it likes better, and try again with that. */
+ anon_start = VG_(am_get_advisory_client_simple)
+ ( 0/*floating*/, anon_size+resvn_size, &ok );
+ if (ok) {
+ resvn_start = anon_start + anon_size;
+ ok = VG_(am_create_reservation)(
+ resvn_start,
+ resvn_size,
+ SmLower,
+ anon_size
+ );
+ if (ok)
+ VG_(brk_base) = VG_(brk_limit) = anon_start;
+ }
+ /* that too might have failed, but if it has, we're hosed: there
+ is no Plan C. */
+ }
+ vg_assert(ok);
+
+ /* We make the data segment (heap) executable because LinuxThreads on
+ ppc32 creates trampolines in this area. Also, on x86/Linux the data
+ segment is RWX natively, at least according to /proc/self/maps.
+ Also, having a non-executable data seg would kill any program which
+ tried to create code in the data seg and then run it. */
+ sres = VG_(am_mmap_anon_fixed_client)(
+ anon_start,
+ anon_size,
+ VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC
+ );
+ vg_assert(!sres.isError);
+ vg_assert(sres.res == anon_start);
+}
+
+
+/*====================================================================*/
+/*=== TOP-LEVEL: VG_(setup_client_initial_image) ===*/
+/*====================================================================*/
+
+/* Create the client's initial memory image. */
+IIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo iicii )
+{
+ ExeInfo info;
+ HChar** env = NULL;
+
+ IIFinaliseImageInfo iifii;
+ VG_(memset)( &iifii, 0, sizeof(iifii) );
+
+ //--------------------------------------------------------------
+ // Load client executable, finding in $PATH if necessary
+ // p: get_helprequest_and_toolname() [for 'exec', 'need_help']
+ // p: layout_remaining_space [so there's space]
+ //--------------------------------------------------------------
+ VG_(debugLog)(1, "initimg", "Loading client\n");
+
+ if (VG_(args_the_exename) == NULL)
+ VG_(err_missing_prog)();
+
+ load_client(&info, &iifii.initial_client_IP, &iifii.initial_client_TOC);
+
+ //--------------------------------------------------------------
+ // Set up client's environment
+ // p: set-libdir [for VG_(libdir)]
+ // p: get_helprequest_and_toolname [for toolname]
+ //--------------------------------------------------------------
+ VG_(debugLog)(1, "initimg", "Setup client env\n");
+ env = setup_client_env(iicii.envp, iicii.toolname);
+
+ //--------------------------------------------------------------
+ // Setup client stack, eip, and VG_(client_arg[cv])
+ // p: load_client() [for 'info']
+ // p: fix_environment() [for 'env']
+ //--------------------------------------------------------------
+ {
+ /* When allocating space for the client stack on Linux, take
+ notice of the --main-stacksize value. This makes it possible
+ to run programs with very large (primary) stack requirements
+ simply by specifying --main-stacksize. */
+ /* Logic is as follows:
+ - by default, use the client's current stack rlimit
+ - if that exceeds 16M, clamp to 16M
+ - if a larger --main-stacksize value is specified, use that instead
+ - in all situations, the minimum allowed stack size is 1M
+ */
+ void* init_sp = iicii.argv - 1;
+ SizeT m1 = 1024 * 1024;
+ SizeT m16 = 16 * m1;
+ SizeT szB = (SizeT)VG_(client_rlimit_stack).rlim_cur;
+ if (szB < m1) szB = m1;
+ if (szB > m16) szB = m16;
+ if (VG_(clo_main_stacksize) > 0) szB = VG_(clo_main_stacksize);
+ if (szB < m1) szB = m1;
+ szB = VG_PGROUNDUP(szB);
+ VG_(debugLog)(1, "initimg",
+ "Setup client stack: size will be %ld\n", szB);
+
+ iifii.clstack_max_size = szB;
+
+ iifii.initial_client_SP
+ = setup_client_stack( init_sp, env,
+ &info, &iifii.client_auxv,
+ iicii.clstack_top, iifii.clstack_max_size );
+
+ VG_(free)(env);
+
+ VG_(debugLog)(2, "initimg",
+ "Client info: "
+ "initial_IP=%p initial_TOC=%p brk_base=%p\n",
+ (void*)(iifii.initial_client_IP),
+ (void*)(iifii.initial_client_TOC),
+ (void*)VG_(brk_base) );
+ VG_(debugLog)(2, "initimg",
+ "Client info: "
+ "initial_SP=%p max_stack_size=%ld\n",
+ (void*)(iifii.initial_client_SP),
+ (SizeT)iifii.clstack_max_size );
+ }
+
+ //--------------------------------------------------------------
+ // Setup client data (brk) segment. Initially a 1-page segment
+ // which abuts a shrinkable reservation.
+ // p: load_client() [for 'info' and hence VG_(brk_base)]
+ //--------------------------------------------------------------
+ {
+ SizeT m1 = 1024 * 1024;
+ SizeT m8 = 8 * m1;
+ SizeT dseg_max_size = (SizeT)VG_(client_rlimit_data).rlim_cur;
+ VG_(debugLog)(1, "initimg", "Setup client data (brk) segment\n");
+ if (dseg_max_size < m1) dseg_max_size = m1;
+ if (dseg_max_size > m8) dseg_max_size = m8;
+ dseg_max_size = VG_PGROUNDUP(dseg_max_size);
+
+ setup_client_dataseg( dseg_max_size );
+ }
+
+ return iifii;
+}
+
+
+/*====================================================================*/
+/*=== TOP-LEVEL: VG_(finalise_thread1state) ===*/
+/*====================================================================*/
+
+/* Just before starting the client, we may need to make final
+ adjustments to its initial image. Also we need to set up the VEX
+ guest state for thread 1 (the root thread) and copy in essential
+ starting values. This is handed the IIFinaliseImageInfo created by
+ VG_(ii_create_image).
+*/
+void VG_(ii_finalise_image)( IIFinaliseImageInfo iifii )
+{
+ ThreadArchState* arch = &VG_(threads)[1].arch;
+
+ /* On Linux we get client_{ip/sp/toc}, and start the client with
+ all other registers zeroed. */
+
+# if defined(VGP_x86_linux)
+ vg_assert(0 == sizeof(VexGuestX86State) % 16);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestX86_initialise(&arch->vex);
+
+ /* Zero out the shadow areas. */
+ VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestX86State));
+ VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestX86State));
+
+ /* Put essential stuff into the new state. */
+ arch->vex.guest_ESP = iifii.initial_client_SP;
+ arch->vex.guest_EIP = iifii.initial_client_IP;
+
+ /* initialise %cs, %ds and %ss to point at the operating systems
+ default code, data and stack segments */
+ asm volatile("movw %%cs, %0" : : "m" (arch->vex.guest_CS));
+ asm volatile("movw %%ds, %0" : : "m" (arch->vex.guest_DS));
+ asm volatile("movw %%ss, %0" : : "m" (arch->vex.guest_SS));
+
+# elif defined(VGP_amd64_linux)
+ vg_assert(0 == sizeof(VexGuestAMD64State) % 16);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestAMD64_initialise(&arch->vex);
+
+ /* Zero out the shadow areas. */
+ VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestAMD64State));
+ VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestAMD64State));
+
+ /* Put essential stuff into the new state. */
+ arch->vex.guest_RSP = iifii.initial_client_SP;
+ arch->vex.guest_RIP = iifii.initial_client_IP;
+
+# elif defined(VGP_ppc32_linux)
+ vg_assert(0 == sizeof(VexGuestPPC32State) % 16);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestPPC32_initialise(&arch->vex);
+
+ /* Zero out the shadow areas. */
+ VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestPPC32State));
+ VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestPPC32State));
+
+ /* Put essential stuff into the new state. */
+ arch->vex.guest_GPR1 = iifii.initial_client_SP;
+ arch->vex.guest_CIA = iifii.initial_client_IP;
+
+# elif defined(VGP_ppc64_linux)
+ vg_assert(0 == sizeof(VexGuestPPC64State) % 16);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestPPC64_initialise(&arch->vex);
+
+ /* Zero out the shadow areas. */
+ VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestPPC64State));
+ VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestPPC64State));
+
+ /* Put essential stuff into the new state. */
+ arch->vex.guest_GPR1 = iifii.initial_client_SP;
+ arch->vex.guest_GPR2 = iifii.initial_client_TOC;
+ arch->vex.guest_CIA = iifii.initial_client_IP;
+
+# else
+# error Unknown platform
+# endif
+
+ /* Tell the tool that we just wrote to the registers. */
+ VG_TRACK( post_reg_write, Vg_CoreStartup, /*tid*/1, /*offset*/0,
+ sizeof(VexGuestArchState));
+}
+
+
+/*--------------------------------------------------------------------*/
+/*--- initimg-linux.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_initimg/simple_huffman.c b/coregrind/m_initimg/simple_huffman.c
new file mode 100644
index 0000000..f9f3bb5
--- /dev/null
+++ b/coregrind/m_initimg/simple_huffman.c
@@ -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;
+ }
+ }
+ }
+}