diff options
Diffstat (limited to 'coregrind/m_initimg')
-rw-r--r-- | coregrind/m_initimg/.svn/entries | 64 | ||||
-rw-r--r-- | coregrind/m_initimg/.svn/format | 1 | ||||
-rw-r--r-- | coregrind/m_initimg/.svn/text-base/initimg-aix5.c.svn-base | 545 | ||||
-rw-r--r-- | coregrind/m_initimg/.svn/text-base/initimg-linux.c.svn-base | 1074 | ||||
-rw-r--r-- | coregrind/m_initimg/.svn/text-base/simple_huffman.c.svn-base | 513 | ||||
-rw-r--r-- | coregrind/m_initimg/initimg-aix5.c | 545 | ||||
-rw-r--r-- | coregrind/m_initimg/initimg-linux.c | 1074 | ||||
-rw-r--r-- | coregrind/m_initimg/simple_huffman.c | 513 |
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; + } + } + } +} |