|
From: <sv...@va...> - 2006-10-01 12:38:16
|
Author: sewardj
Date: 2006-10-01 13:38:12 +0100 (Sun, 01 Oct 2006)
New Revision: 6104
Log:
Initial-image creation stuff for Linux. This all used to be in
m_main.c. Perhaps in the future m_ume.c should be folded into this.
Added:
branches/AIX5/coregrind/m_initimg/initimg-linux.c
Added: branches/AIX5/coregrind/m_initimg/initimg-linux.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- branches/AIX5/coregrind/m_initimg/initimg-linux.c =
(rev 0)
+++ branches/AIX5/coregrind/m_initimg/initimg-linux.c 2006-10-01 12:38:12=
UTC (rev 6104)
@@ -0,0 +1,998 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Startup: create initial process image on Linux ---*/
+/*--- initimg-linux.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2006 Julian Seward
+ js...@ac...
+
+ 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_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_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 --- !!! --- */
+
+
+/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/
+/*=3D=3D=3D Find executable =
=3D=3D=3D*/
+/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/
+
+/* 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 =3D=3D NULL ||
+ *colsep =3D=3D '\0')
+ return False;
+
+ entry =3D cp =3D colsep;
+
+ do {
+ end =3D (*cp =3D=3D '\0');
+
+ if (*cp =3D=3D ':' || *cp =3D=3D '\0') {
+ char save =3D *cp;
+
+ *cp =3D '\0';
+ if ((*func)(entry)) {
+ *cp =3D save;
+ return True;
+ }
+ *cp =3D save;
+ entry =3D 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)=20
+{
+ HChar buf[VG_(strlen)(entry) + VG_(strlen)(executable_name_in) + 3];
+
+ /* empty PATH element means '.' */
+ if (*entry =3D=3D '\0')
+ entry =3D ".";
+
+ 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*/) =3D=3D 0) {
+ VG_(strncpy)( executable_name_out, buf, VKI_PATH_MAX-1 );
+ executable_name_out[VKI_PATH_MAX-1] =3D 0;
+ return True; // Stop looking
+ } else if (VG_(access)(buf, True/*r*/, False/*w*/, False/*x*/) =3D=3D=
0=20
+ && VG_STREQ(executable_name_out, ""))=20
+ {
+ VG_(strncpy)( executable_name_out, buf, VKI_PATH_MAX-1 );
+ executable_name_out[VKI_PATH_MAX-1] =3D 0;
+ return False; // Keep looking
+ } else {=20
+ return False; // Keep looking
+ }
+}
+
+// Returns NULL if it wasn't found.
+static HChar* find_executable ( HChar* exec )
+{
+ vg_assert(NULL !=3D 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 =3D VG_(getenv)("PATH");
+ scan_colsep(path, match_executable);
+ }
+ return VG_STREQ(executable_name_out, "") ? NULL : executable_name_out=
;
+}
+
+
+/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/
+/*=3D=3D=3D Loading the client =
=3D=3D=3D*/
+/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/
+
+/* Load the client whose name is VG_(argv_the_exename). */
+
+static void load_client ( /*OUT*/ExeInfo* info,=20
+ /*OUT*/Addr* client_ip,
+ /*OUT*/Addr* client_toc)
+{
+ HChar* exe_name;
+ Int ret;
+ SysRes res;
+
+ vg_assert( VG_(args_the_exename) !=3D NULL);
+ exe_name =3D find_executable( VG_(args_the_exename) );
+
+ if (!exe_name) {
+ VG_(printf)("valgrind: %s: command not found\n", VG_(args_the_exen=
ame));
+ VG_(exit)(127); // 127 is Posix NOTFOUND
+ }
+
+ VG_(memset)(info, 0, sizeof(*info));
+ info->exe_base =3D VG_(client_base);
+ info->exe_end =3D VG_(client_end);
+
+ ret =3D VG_(do_exec)(exe_name, info);
+
+ // 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 =3D VG_(open)(exe_name, VKI_O_RDONLY, VKI_S_IRUSR);
+ if (!res.isError)
+ VG_(cl_exec_fd) =3D res.res;
+
+ /* Copy necessary bits of 'info' that were filled in */
+ *client_ip =3D info->init_ip;
+ *client_toc =3D info->init_toc;
+ VG_(brk_base) =3D VG_(brk_limit) =3D VG_PGROUNDUP(info->brkbase);
+}
+
+
+/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/
+/*=3D=3D=3D Setting up the client's environment =
=3D=3D=3D*/
+/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/
+
+/* Prepare the client's environment. This is basically a copy of our
+ environment, except:
+
+ LD_PRELOAD=3D$VALGRIND_LIB/PLATFORM/vgpreload_core.so:
+ ($VALGRIND_LIB/PLATFORM/vgpreload_TOOL.so:)?
+ $LD_PRELOAD
+
+ If this is missing, then it is added.
+
+ Also, remove any binding for VALGRIND_LAUNCHER=3D. 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 =3D "vgpreload_core";
+ HChar* ld_preload =3D "LD_PRELOAD=3D";
+ HChar* v_launcher =3D VALGRIND_LAUNCHER "=3D";
+ Int ld_preload_len =3D VG_(strlen)( ld_preload );
+ Int v_launcher_len =3D VG_(strlen)( v_launcher );
+ Bool ld_preload_done =3D False;
+ Int vglib_len =3D 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 i=
t
+ doesn't hurt to over-allocate briefly. The 16s are just cautious
+ slop. */
+ Int preload_core_path_len =3D vglib_len + sizeof(preload_core)=20
+ + sizeof(VG_PLATFORM) + 16;
+ Int preload_tool_path_len =3D vglib_len + VG_(strlen)(toolname)=20
+ + sizeof(VG_PLATFORM) + 16;
+ Int preload_string_len =3D preload_core_path_len + preload_tool_pa=
th_len;
+ HChar* preload_string =3D VG_(malloc)(preload_string_len);
+ vg_assert(preload_string);
+
+ /* Determine if there's a vgpreload_<tool>.so file, and setup
+ preload_string. */
+ preload_tool_path =3D VG_(malloc)(preload_tool_path_len);
+ vg_assert(preload_tool_path);
+ VG_(snprintf)(preload_tool_path, preload_tool_path_len,
+ "%s/%s/vgpreload_%s.so", VG_(libdir), VG_PLATFORM, tool=
name);
+ if (VG_(access)(preload_tool_path, True/*r*/, False/*w*/, False/*x*/)=
=3D=3D 0) {
+ VG_(snprintf)(preload_string, preload_string_len, "%s/%s/%s.so:%s"=
,=20
+ VG_(libdir), VG_PLATFORM, preload_core, preload_tool=
_path);
+ } else {
+ VG_(snprintf)(preload_string, preload_string_len, "%s/%s/%s.so",=20
+ VG_(libdir), VG_PLATFORM, preload_core);
+ }
+ 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 =3D 0;
+ for (cpp =3D origenv; cpp && *cpp; cpp++)
+ envc++;
+
+ /* Allocate a new space */
+ ret =3D VG_(malloc) (sizeof(HChar *) * (envc+1+1)); /* 1 new entry + =
NULL */
+ vg_assert(ret);
+
+ /* copy it over */
+ for (cpp =3D ret; *origenv; )
+ *cpp++ =3D *origenv++;
+ *cpp =3D NULL;
+ =20
+ vg_assert(envc =3D=3D (cpp - ret));
+
+ /* Walk over the new environment, mashing as we go */
+ for (cpp =3D ret; cpp && *cpp; cpp++) {
+ if (VG_(memcmp)(*cpp, ld_preload, ld_preload_len) =3D=3D 0) {
+ Int len =3D VG_(strlen)(*cpp) + preload_string_len;
+ HChar *cp =3D VG_(malloc)(len);
+ vg_assert(cp);
+
+ VG_(snprintf)(cp, len, "%s%s:%s",
+ ld_preload, preload_string, (*cpp)+ld_preload_len=
);
+
+ *cpp =3D cp;
+
+ ld_preload_done =3D True;
+ }
+ }
+
+ /* Add the missing bits */
+ if (!ld_preload_done) {
+ Int len =3D ld_preload_len + preload_string_len;
+ HChar *cp =3D VG_(malloc) (len);
+ vg_assert(cp);
+
+ VG_(snprintf)(cp, len, "%s%s", ld_preload, preload_string);
+
+ ret[envc++] =3D cp;
+ }
+
+ /* ret[0 .. envc-1] is live now. */
+ /* Find and remove a binding for VALGRIND_LAUNCHER. */
+ for (i =3D 0; i < envc; i++)
+ if (0 =3D=3D VG_(memcmp(ret[i], v_launcher, v_launcher_len)))
+ break;
+
+ if (i < envc) {
+ for (; i < envc-1; i++)
+ ret[i] =3D ret[i+1];
+ envc--;
+ }
+
+ VG_(free)(preload_string);
+ ret[envc] =3D NULL;
+
+ return ret;
+}
+
+
+/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/
+/*=3D=3D=3D Setting up the client's stack =
=3D=3D=3D*/
+/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/
+
+#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 =3D *tab;
+ char *orig =3D cp;
+
+ while(*str)
+ *cp++ =3D *str++;
+ *cp++ =3D '\0';
+
+ if (0)
+ VG_(printf)("copied %p \"%s\" len %lld\n", orig, orig, (Long)(cp-o=
rig));
+
+ *tab =3D cp;
+
+ return orig;
+}
+
+
+/* ----------------------------------------------------------------
+=20
+ 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?
+
+ ---------------------------------------------------------------- */
+
+static=20
+Addr setup_client_stack( void* init_sp,
+ char** orig_envp,=20
+ 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 ume_auxv *auxv;
+ const struct ume_auxv *orig_auxv;
+ const struct ume_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));
+
+ /* use our own auxv as a prototype */
+ orig_auxv =3D VG_(find_auxv)(init_sp);
+
+ /* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D compu=
te sizes =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D */
+
+ /* first of all, work out how big the client stack will be */
+ stringsize =3D 0;
+ have_exename =3D VG_(args_the_exename) !=3D NULL;
+
+ /* paste on the extra args if the loader needs them (ie, the #!=20
+ interpreter and its argument) */
+ argc =3D 0;
+ if (info->interp_name !=3D NULL) {
+ argc++;
+ stringsize +=3D VG_(strlen)(info->interp_name) + 1;
+ }
+ if (info->interp_args !=3D NULL) {
+ argc++;
+ stringsize +=3D VG_(strlen)(info->interp_args) + 1;
+ }
+
+ /* now scan the args we're given... */
+ if (have_exename)
+ stringsize +=3D VG_(strlen)( VG_(args_the_exename) ) + 1;
+
+ for (i =3D 0; i < VG_(args_for_client).used; i++) {
+ argc++;
+ stringsize +=3D VG_(strlen)( VG_(args_for_client).strs[i] ) + 1;
+ }
+
+ /* ...and the environment */
+ envc =3D 0;
+ for (cpp =3D orig_envp; cpp && *cpp; cpp++) {
+ envc++;
+ stringsize +=3D VG_(strlen)(*cpp) + 1;
+ }
+
+ /* now, how big is the auxv? */
+ auxsize =3D sizeof(*auxv); /* there's always at least one entry: AT_N=
ULL */
+ for (cauxv =3D orig_auxv; cauxv->a_type !=3D AT_NULL; cauxv++) {
+ if (cauxv->a_type =3D=3D AT_PLATFORM)
+ stringsize +=3D VG_(strlen)(cauxv->u.a_ptr) + 1;
+ auxsize +=3D sizeof(*cauxv);
+ }
+
+# if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
+ auxsize +=3D 2 * sizeof(*cauxv);
+# endif
+
+ /* OK, now we know how big the client stack is */
+ stacksize =3D
+ sizeof(Word) + /* argc */
+ (have_exename ? sizeof(char **) : 0) + /* argc[0] =3D=3D 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 =3D %d\n", stacksize);
+
+ /* client_SP is the client's stack pointer */
+ client_SP =3D clstack_end - stacksize;
+ client_SP =3D VG_ROUNDDN(client_SP, 16); /* make stack 16 byte aligne=
d */
+
+ /* base of the string table (aligned) */
+ stringbase =3D strtab =3D (char *)clstack_end=20
+ - VG_ROUNDUP(stringsize, sizeof(int));
+
+ clstack_start =3D VG_PGROUNDDN(client_SP);
+
+ /* The max stack size */
+ clstack_max_size =3D VG_PGROUNDUP(clstack_max_size);
+
+ /* Record stack extent -- needed for stack-change code. */
+ VG_(clstk_base) =3D clstack_start;
+ VG_(clstk_end) =3D clstack_end;
+
+ if (0)
+ VG_(printf)("stringsize=3D%d auxsize=3D%d stacksize=3D%d maxsize=3D=
0x%x\n"
+ "clstack_start %p\n"
+ "clstack_end %p\n",
+ stringsize, auxsize, stacksize, (Int)clstack_max_size,
+ (void*)clstack_start, (void*)clstack_end);
+
+ /* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D alloc=
ate space =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D */
+
+ { SizeT anon_size =3D clstack_end - clstack_start + 1;
+ SizeT resvn_size =3D clstack_max_size - anon_size;
+ Addr anon_start =3D clstack_start;
+ Addr resvn_start =3D anon_start - resvn_size;
+ SizeT inner_HACK =3D 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 >=3D 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 -=3D VKI_PAGE_SIZE;
+ anon_start -=3D VKI_PAGE_SIZE;
+ anon_size +=3D 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 =3D=3D clstack_end + 1 - clstack_max_size);
+
+# ifdef ENABLE_INNER
+ inner_HACK =3D 1024*1024; // create 1M non-fault-extending stack
+# endif
+
+ if (0)
+ VG_(printf)("%p 0x%x %p 0x%x\n",=20
+ resvn_start, resvn_size, anon_start, anon_size);
+
+ /* Create a shrinkable reservation followed by an anonymous
+ segment. Together these constitute a growdown stack. */
+ ok =3D VG_(am_create_reservation)(
+ resvn_start,
+ resvn_size -inner_HACK,
+ SmUpper,=20
+ anon_size +inner_HACK
+ );
+ vg_assert(ok);
+ /* allocate a stack - mmap enough space for the stack */
+ res =3D VG_(am_mmap_anon_fixed_client)(
+ anon_start -inner_HACK,
+ anon_size +inner_HACK,
+ VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC
+ );
+ vg_assert(!res.isError);=20
+ }
+
+ /* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D creat=
e client stack =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
*/
+
+ ptr =3D (Addr*)client_SP;
+
+ /* --- client argc --- */
+ *ptr++ =3D argc + (have_exename ? 1 : 0);
+
+ /* --- client argv --- */
+ if (info->interp_name) {
+ *ptr++ =3D (Addr)copy_str(&strtab, info->interp_name);
+ VG_(free)(info->interp_name);
+ }
+ if (info->interp_args) {
+ *ptr++ =3D (Addr)copy_str(&strtab, info->interp_args);
+ VG_(free)(info->interp_args);
+ }
+
+ if (have_exename)
+ *ptr++ =3D (Addr)copy_str(&strtab, VG_(args_the_exename));
+
+ for (i =3D 0; i < VG_(args_for_client).used; i++) {
+ *ptr++ =3D (Addr)copy_str(&strtab, VG_(args_for_client).strs[i]);
+ }
+ *ptr++ =3D 0;
+
+ /* --- envp --- */
+ VG_(client_envp) =3D (Char **)ptr;
+ for (cpp =3D orig_envp; cpp && *cpp; ptr++, cpp++)
+ *ptr =3D (Addr)copy_str(&strtab, *cpp);
+ *ptr++ =3D 0;
+
+ /* --- auxv --- */
+ auxv =3D (struct ume_auxv *)ptr;
+ *client_auxv =3D (UInt *)auxv;
+
+# if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
+ auxv[0].a_type =3D AT_IGNOREPPC;
+ auxv[0].u.a_val =3D AT_IGNOREPPC;
+ auxv[1].a_type =3D AT_IGNOREPPC;
+ auxv[1].u.a_val =3D AT_IGNOREPPC;
+ auxv +=3D 2;
+# endif
+
+ for (; orig_auxv->a_type !=3D AT_NULL; auxv++, orig_auxv++) {
+
+ /* copy the entry... */
+ *auxv =3D *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 =3D=3D 0)
+ auxv->a_type =3D AT_IGNORE;
+ else
+ auxv->u.a_val =3D info->phdr;
+ break;
+
+ case AT_PHNUM:
+ if (info->phdr =3D=3D 0)
+ auxv->a_type =3D AT_IGNORE;
+ else
+ auxv->u.a_val =3D info->phnum;
+ break;
+
+ case AT_BASE:
+ auxv->u.a_val =3D info->interp_base;
+ break;
+
+ case AT_PLATFORM:
+ /* points to a platform description string */
+ auxv->u.a_ptr =3D copy_str(&strtab, orig_auxv->u.a_ptr);
+ break;
+
+ case AT_ENTRY:
+ auxv->u.a_val =3D 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",=20
+ "PPC32 cache line size %u (type %u)\n",=20
+ (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",=20
+ "PPC64 cache line size %u (type %u)\n",=20
+ (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 =3D 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 =3D AT_IGNORE;
+ break;
+
+ default:
+ /* stomp out anything we don't know about */
+ VG_(debugLog)(2, "initimg",
+ "stomping auxv entry %lld\n",=20
+ (ULong)auxv->a_type);
+ auxv->a_type =3D AT_IGNORE;
+ break;
+ }
+ }
+ *auxv =3D *orig_auxv;
+ vg_assert(auxv->a_type =3D=3D AT_NULL);
+
+ vg_assert((strtab-stringbase) =3D=3D stringsize);
+
+ /* client_SP is pointing at client's argc/argv */
+
+ if (0) VG_(printf)("startup SP =3D %p\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 =3D VG_(brk_base);
+ SizeT anon_size =3D VKI_PAGE_SIZE;
+ Addr resvn_start =3D anon_start + anon_size;
+ SizeT resvn_size =3D 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) =3D=3D VG_(brk_limit));
+
+ /* Try to create the data seg and associated reservation where
+ VG_(brk_base) says. */
+ ok =3D VG_(am_create_reservation)(=20
+ resvn_start,=20
+ resvn_size,=20
+ SmLower,=20
+ 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 =3D VG_(am_get_advisory_client_simple)
+ ( 0/*floating*/, anon_size+resvn_size, &ok );
+ if (ok) {
+ resvn_start =3D anon_start + anon_size;
+ ok =3D VG_(am_create_reservation)(=20
+ resvn_start,=20
+ resvn_size,=20
+ SmLower,=20
+ anon_size
+ );
+ if (ok)
+ VG_(brk_base) =3D VG_(brk_limit) =3D 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 da=
ta
+ segment is RWX natively, at least according to /proc/self/maps.
+ Also, having a non-executable data seg would kill any program whic=
h
+ tried to create code in the data seg and then run it. */
+ sres =3D VG_(am_mmap_anon_fixed_client)(=20
+ anon_start,=20
+ anon_size,=20
+ VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC
+ );
+ vg_assert(!sres.isError);
+ vg_assert(sres.res =3D=3D anon_start);
+}
+
+
+/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/
+/*=3D=3D=3D TOP-LEVEL: VG_(setup_client_initial_image) =
=3D=3D=3D*/
+/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/
+
+/* Create the client's initial memory image. */
+
+ClientInitImgInfo
+ VG_(setup_client_initial_image)(
+ /*IN*/ HChar** argv,
+ /*IN*/ HChar** envp,
+ /*IN*/ HChar* toolname,
+ /*IN*/ Addr clstack_top,
+ /*IN*/ SizeT clstack_max_size
+ )
+{
+ ClientInitImgInfo ciii =3D { 0, 0, 0, NULL };
+ ExeInfo info;
+ HChar** env =3D NULL;
+
+ //--------------------------------------------------------------
+ // 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) =3D=3D NULL)
+ VG_(err_missing_prog)();
+
+ load_client(&info, &ciii.initial_client_IP, &ciii.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 =3D setup_client_env(envp, toolname);
+
+ //--------------------------------------------------------------
+ // Setup client stack, eip, and VG_(client_arg[cv])
+ // p: load_client() [for 'info']
+ // p: fix_environment() [for 'env']
+ //--------------------------------------------------------------
+ {
+ void* init_sp =3D argv - 1;
+ SizeT m1 =3D 1024 * 1024;
+ SizeT m16 =3D 16 * m1;
+ VG_(debugLog)(1, "initimg", "Setup client stack\n");
+ clstack_max_size =3D (SizeT)VG_(client_rlimit_stack).rlim_cur;
+ if (clstack_max_size < m1) clstack_max_size =3D m1;
+ if (clstack_max_size > m16) clstack_max_size =3D m16;
+ clstack_max_size =3D VG_PGROUNDUP(clstack_max_size);
+
+ ciii.initial_client_SP
+ =3D setup_client_stack( init_sp, env,=20
+ &info, &ciii.client_auxv,=20
+ clstack_top, clstack_max_size );
+
+ VG_(free)(env);
+
+ VG_(debugLog)(2, "initimg",
+ "Client info: "
+ "initial_IP=3D%p initial_SP=3D%p initial_TOC=3D%p=
brk_base=3D%p\n",
+ (void*)(ciii.initial_client_IP),=20
+ (void*)(ciii.initial_client_SP),
+ (void*)(ciii.initial_client_TOC),
+ (void*)VG_(brk_base) );
+ }
+
+ //--------------------------------------------------------------
+ // Setup client data (brk) segment. Initially a 1-page segment
+ // which abuts a shrinkable reservation.=20
+ // p: load_client() [for 'info' and hence VG_(brk_base)]
+ //--------------------------------------------------------------
+ {=20
+ SizeT m1 =3D 1024 * 1024;
+ SizeT m8 =3D 8 * m1;
+ SizeT dseg_max_size =3D (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 =3D m1;
+ if (dseg_max_size > m8) dseg_max_size =3D m8;
+ dseg_max_size =3D VG_PGROUNDUP(dseg_max_size);
+
+ setup_client_dataseg( dseg_max_size );
+ }
+
+ return ciii;
+}
+
+
+/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/
+/*=3D=3D=3D TOP-LEVEL: VG_(finalise_thread1state) =
=3D=3D=3D*/
+/*=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/
+
+/* Make final adjustments to the initial image. Also, initialise the
+ VEX guest state for thread 1 (the root thread) and copy in
+ essential starting values. Is handed the ClientInitImgInfo created
+ by VG_(setup_client_initial_image). Upon return, the client's
+ memory and register state should be ready to start the JIT. */
+extern=20
+void VG_(finalise_thread1state)( /*MOD*/ThreadArchState* arch,
+ ClientInitImgInfo ciii )
+{
+ /* 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 =3D=3D sizeof(VexGuestX86State) % 8);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestX86_initialise(&arch->vex);
+
+ /* Zero out the shadow area. */
+ VG_(memset)(&arch->vex_shadow, 0, sizeof(VexGuestX86State));
+
+ /* Put essential stuff into the new state. */
+ arch->vex.guest_ESP =3D ciii.initial_client_SP;
+ arch->vex.guest_EIP =3D ciii.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 =3D=3D sizeof(VexGuestAMD64State) % 8);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestAMD64_initialise(&arch->vex);
+
+ /* Zero out the shadow area. */
+ VG_(memset)(&arch->vex_shadow, 0, sizeof(VexGuestAMD64State));
+
+ /* Put essential stuff into the new state. */
+ arch->vex.guest_RSP =3D ciii.initial_client_SP;
+ arch->vex.guest_RIP =3D ciii.initial_client_IP;
+
+# elif defined(VGP_ppc32_linux)
+ vg_assert(0 =3D=3D sizeof(VexGuestPPC32State) % 8);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestPPC32_initialise(&arch->vex);
+
+ /* Zero out the shadow area. */
+ VG_(memset)(&arch->vex_shadow, 0, sizeof(VexGuestPPC32State));
+
+ /* Put essential stuff into the new state. */
+ arch->vex.guest_GPR1 =3D ciii.initial_client_SP;
+ arch->vex.guest_CIA =3D ciii.initial_client_IP;
+
+# elif defined(VGP_ppc64_linux)
+ vg_assert(0 =3D=3D 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 area. */
+ VG_(memset)(&arch->vex_shadow, 0, sizeof(VexGuestPPC64State));
+
+ /* Put essential stuff into the new state. */
+ arch->vex.guest_GPR1 =3D ciii.initial_client_SP;
+ arch->vex.guest_GPR2 =3D ciii.initial_client_TOC;
+ arch->vex.guest_CIA =3D ciii.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 ---*/
+/*--------------------------------------------------------------------*/
|