1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Startup: create initial process image on Linux               ---*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                              initimg-linux.c ---*/
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of Valgrind, a dynamic binary instrumentation
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   framework.
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Copyright (C) 2000-2013 Julian Seward
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jseward@acm.org
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is free software; you can redistribute it and/or
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU General Public License as
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is distributed in the hope that it will be useful, but
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WITHOUT ANY WARRANTY; without even the implied warranty of
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   General Public License for more details.
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU General Public License
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   along with this program; if not, write to the Free Software
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   02111-1307, USA.
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU General Public License is contained in the file COPYING.
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_linux)
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_basics.h"
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_vki.h"
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_debuglog.h"
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcbase.h"
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcassert.h"
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcfile.h"
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcproc.h"
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcprint.h"
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_xarray.h"
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_clientstate.h"
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_aspacemgr.h"
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_mallocfree.h"
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_machine.h"
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_ume.h"
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_options.h"
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_syscall.h"
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_tooliface.h"       /* VG_TRACK */
51b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include "pub_core_libcsetjmp.h"      // to keep _threadstate.h happy
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_threadstate.h"     /* ThreadArchState */
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_initimg_pathscan.h"
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_initimg.h"         /* self */
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define _GNU_SOURCE
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define _FILE_OFFSET_BITS 64
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is for ELF types etc, and also the AT_ constants. */
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <elf.h>
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*====================================================================*/
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*=== Loading the client                                           ===*/
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*====================================================================*/
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Load the client whose name is VG_(argv_the_exename). */
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void load_client ( /*OUT*/ExeInfo* info,
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          /*OUT*/Addr*    client_ip,
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  /*OUT*/Addr*    client_toc)
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
74436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   const HChar* exe_name;
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    ret;
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert( VG_(args_the_exename) != NULL);
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   exe_name = ML_(find_executable)( VG_(args_the_exename) );
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!exe_name) {
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("valgrind: %s: command not found\n", VG_(args_the_exename));
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(exit)(127);      // 127 is Posix NOTFOUND
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(info, 0, sizeof(*info));
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ret = VG_(do_exec)(exe_name, info);
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ret < 0) {
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("valgrind: could not execute '%s'\n", exe_name);
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(exit)(1);
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // The client was successfully loaded!  Continue.
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Get hold of a file descriptor which refers to the client
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      executable.  This is needed for attaching to GDB. */
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(open)(exe_name, VKI_O_RDONLY, VKI_S_IRUSR);
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!sr_isError(res))
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(cl_exec_fd) = sr_Res(res);
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Copy necessary bits of 'info' that were filled in */
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *client_ip  = info->init_ip;
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *client_toc = info->init_toc;
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(brk_base) = VG_(brk_limit) = VG_PGROUNDUP(info->brkbase);
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*====================================================================*/
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*=== Setting up the client's environment                          ===*/
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*====================================================================*/
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Prepare the client's environment.  This is basically a copy of our
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   environment, except:
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     LD_PRELOAD=$VALGRIND_LIB/vgpreload_core-PLATFORM.so:
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ($VALGRIND_LIB/vgpreload_TOOL-PLATFORM.so:)?
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $LD_PRELOAD
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If this is missing, then it is added.
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Also, remove any binding for VALGRIND_LAUNCHER=.  The client should
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   not be able to see this.
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If this needs to handle any more variables it should be hacked
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   into something table driven.  The copy is VG_(malloc)'d space.
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar** setup_client_env ( HChar** origenv, const HChar* toolname)
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
129436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   const HChar* preload_core    = "vgpreload_core";
130436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   const HChar* ld_preload      = "LD_PRELOAD=";
131436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   const HChar* v_launcher      = VALGRIND_LAUNCHER "=";
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    ld_preload_len  = VG_(strlen)( ld_preload );
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    v_launcher_len  = VG_(strlen)( v_launcher );
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   ld_preload_done = False;
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    vglib_len       = VG_(strlen)(VG_(libdir));
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   debug           = False;
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar** cpp;
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar** ret;
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar*  preload_tool_path;
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     envc, i;
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Alloc space for the vgpreload_core.so path and vgpreload_<tool>.so
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      paths.  We might not need the space for vgpreload_<tool>.so, but it
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      doesn't hurt to over-allocate briefly.  The 16s are just cautious
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      slop. */
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int preload_core_path_len = vglib_len + sizeof(preload_core)
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         + sizeof(VG_PLATFORM) + 16;
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int preload_tool_path_len = vglib_len + VG_(strlen)(toolname)
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         + sizeof(VG_PLATFORM) + 16;
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int preload_string_len    = preload_core_path_len + preload_tool_path_len;
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar* preload_string     = VG_(malloc)("initimg-linux.sce.1",
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           preload_string_len);
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(origenv);
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(toolname);
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(preload_string);
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Determine if there's a vgpreload_<tool>_<platform>.so file, and setup
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      preload_string. */
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   preload_tool_path = VG_(malloc)("initimg-linux.sce.2", preload_tool_path_len);
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(preload_tool_path);
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(snprintf)(preload_tool_path, preload_tool_path_len,
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 "%s/vgpreload_%s-%s.so", VG_(libdir), toolname, VG_PLATFORM);
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(access)(preload_tool_path, True/*r*/, False/*w*/, False/*x*/) == 0) {
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so:%s",
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    VG_(libdir), preload_core, VG_PLATFORM, preload_tool_path);
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so",
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    VG_(libdir), preload_core, VG_PLATFORM);
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(free)(preload_tool_path);
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(debugLog)(2, "initimg", "preload_string:\n");
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(debugLog)(2, "initimg", "  \"%s\"\n", preload_string);
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Count the original size of the env */
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (debug) VG_(printf)("\n\n");
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   envc = 0;
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (cpp = origenv; cpp && *cpp; cpp++) {
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      envc++;
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (debug) VG_(printf)("XXXXXXXXX: BEFORE %s\n", *cpp);
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Allocate a new space */
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ret = VG_(malloc) ("initimg-linux.sce.3",
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      sizeof(HChar *) * (envc+1+1)); /* 1 new entry + NULL */
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(ret);
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* copy it over */
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (cpp = ret; *origenv; ) {
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (debug) VG_(printf)("XXXXXXXXX: COPY   %s\n", *origenv);
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *cpp++ = *origenv++;
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *cpp = NULL;
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(envc == (cpp - ret));
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Walk over the new environment, mashing as we go */
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (cpp = ret; cpp && *cpp; cpp++) {
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(memcmp)(*cpp, ld_preload, ld_preload_len) == 0) {
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int len = VG_(strlen)(*cpp) + preload_string_len;
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar *cp = VG_(malloc)("initimg-linux.sce.4", len);
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(cp);
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(snprintf)(cp, len, "%s%s:%s",
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       ld_preload, preload_string, (*cpp)+ld_preload_len);
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *cpp = cp;
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ld_preload_done = True;
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (debug) VG_(printf)("XXXXXXXXX: MASH   %s\n", *cpp);
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Add the missing bits */
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!ld_preload_done) {
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int len = ld_preload_len + preload_string_len;
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar *cp = VG_(malloc) ("initimg-linux.sce.5", len);
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(cp);
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(snprintf)(cp, len, "%s%s", ld_preload, preload_string);
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ret[envc++] = cp;
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (debug) VG_(printf)("XXXXXXXXX: ADD    %s\n", cp);
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ret[0 .. envc-1] is live now. */
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Find and remove a binding for VALGRIND_LAUNCHER. */
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < envc; i++)
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0 == VG_(memcmp(ret[i], v_launcher, v_launcher_len)))
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (i < envc) {
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (; i < envc-1; i++)
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ret[i] = ret[i+1];
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      envc--;
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(free)(preload_string);
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ret[envc] = NULL;
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < envc; i++) {
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (debug) VG_(printf)("XXXXXXXXX: FINAL  %s\n", ret[i]);
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return ret;
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*====================================================================*/
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*=== Setting up the client's stack                                ===*/
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*====================================================================*/
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef AT_ICACHEBSIZE
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define AT_ICACHEBSIZE		20
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif /* AT_ICACHEBSIZE */
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef AT_UCACHEBSIZE
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define AT_UCACHEBSIZE		21
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif /* AT_UCACHEBSIZE */
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef AT_BASE_PLATFORM
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define AT_BASE_PLATFORM	24
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif /* AT_BASE_PLATFORM */
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef AT_RANDOM
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define AT_RANDOM		25
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif /* AT_RANDOM */
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef AT_EXECFN
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define AT_EXECFN		31
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif /* AT_EXECFN */
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef AT_SYSINFO
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define AT_SYSINFO		32
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif /* AT_SYSINFO */
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef AT_SYSINFO_EHDR
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define AT_SYSINFO_EHDR		33
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif /* AT_SYSINFO_EHDR */
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef AT_SECURE
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define AT_SECURE 23   /* secure mode boolean */
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif	/* AT_SECURE */
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Add a string onto the string table, and return its address */
287436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic HChar *copy_str(HChar **tab, const HChar *str)
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
289436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   HChar *cp = *tab;
290436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   HChar *orig = cp;
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while(*str)
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *cp++ = *str++;
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *cp++ = '\0';
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0)
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("copied %p \"%s\" len %lld\n", orig, orig, (Long)(cp-orig));
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *tab = cp;
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return orig;
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ----------------------------------------------------------------
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This sets up the client's initial stack, containing the args,
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   environment and aux vector.
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The format of the stack is:
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   higher address +-----------------+ <- clstack_end
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  |                 |
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  : string table    :
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  |                 |
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  +-----------------+
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  | AT_NULL         |
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  -                 -
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  | auxv            |
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  +-----------------+
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  | NULL            |
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  -                 -
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  | envp            |
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  +-----------------+
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  | NULL            |
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  -                 -
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  | argv            |
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  +-----------------+
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  | argc            |
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   lower address  +-----------------+ <- sp
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  | undefined       |
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		  :                 :
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Allocate and create the initial client stack.  It is allocated down
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   from clstack_end, which was previously determined by the address
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space manager.  The returned value is the SP value for the client.
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The client's auxv is created by copying and modifying our own one.
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   As a side effect of scanning our own auxv, some important bits of
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   info are collected:
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(cache_line_size_ppc32) // ppc32 only -- cache line size
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(have_altivec_ppc32)    // ppc32 only -- is Altivec supported?
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ---------------------------------------------------------------- */
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct auxv
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word a_type;
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   union {
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      void *a_ptr;
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Word a_val;
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } u;
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown};
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct auxv *find_auxv(UWord* sp)
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sp++;                // skip argc (Nb: is word-sized, not int-sized!)
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (*sp != 0)     // skip argv
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sp++;
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sp++;
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (*sp != 0)     // skip env
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sp++;
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sp++;
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGA_ppc32) || defined(VGA_ppc64)
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# if defined AT_IGNOREPPC
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (*sp == AT_IGNOREPPC)        // skip AT_IGNOREPPC entries
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sp += 2;
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# endif
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (struct auxv *)sp;
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownAddr setup_client_stack( void*  init_sp,
381436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                         HChar** orig_envp,
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         const ExeInfo* info,
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         UInt** client_auxv,
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Addr   clstack_end,
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         SizeT  clstack_max_size )
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
388436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   HChar **cpp;
389436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   HChar *strtab;		/* string table */
390436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   HChar *stringbase;
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr *ptr;
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct auxv *auxv;
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const struct auxv *orig_auxv;
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const struct auxv *cauxv;
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unsigned stringsize;		/* total size of strings in bytes */
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unsigned auxsize;		/* total size of auxv in bytes */
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int argc;			/* total argc */
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int envc;			/* total number of env vars */
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unsigned stacksize;		/* total client stack size */
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr client_SP;	        /* client stack base (initial SP) */
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr clstack_start;
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool have_exename;
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_PAGE_ALIGNED(clstack_end+1));
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert( VG_(args_for_client) );
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* use our own auxv as a prototype */
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   orig_auxv = find_auxv(init_sp);
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ==================== compute sizes ==================== */
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* first of all, work out how big the client stack will be */
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stringsize   = 0;
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   have_exename = VG_(args_the_exename) != NULL;
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* paste on the extra args if the loader needs them (ie, the #!
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      interpreter and its argument) */
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   argc = 0;
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (info->interp_name != NULL) {
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argc++;
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stringsize += VG_(strlen)(info->interp_name) + 1;
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (info->interp_args != NULL) {
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argc++;
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stringsize += VG_(strlen)(info->interp_args) + 1;
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* now scan the args we're given... */
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have_exename)
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stringsize += VG_(strlen)( VG_(args_the_exename) ) + 1;
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argc++;
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stringsize += VG_(strlen)( * (HChar**)
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   VG_(indexXA)( VG_(args_for_client), i ))
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    + 1;
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ...and the environment */
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   envc = 0;
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (cpp = orig_envp; cpp && *cpp; cpp++) {
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      envc++;
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stringsize += VG_(strlen)(*cpp) + 1;
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* now, how big is the auxv? */
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   auxsize = sizeof(*auxv);	/* there's always at least one entry: AT_NULL */
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (cauxv = orig_auxv; cauxv->a_type != AT_NULL; cauxv++) {
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (cauxv->a_type == AT_PLATFORM ||
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          cauxv->a_type == AT_BASE_PLATFORM)
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 stringsize += VG_(strlen)(cauxv->u.a_ptr) + 1;
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (cauxv->a_type == AT_RANDOM)
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 stringsize += 16;
455b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      else if (cauxv->a_type == AT_EXECFN && have_exename)
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 stringsize += VG_(strlen)(VG_(args_the_exename)) + 1;
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      auxsize += sizeof(*cauxv);
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   auxsize += 2 * sizeof(*cauxv);
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* OK, now we know how big the client stack is */
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stacksize =
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sizeof(Word) +                          /* argc */
467436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      (have_exename ? sizeof(HChar **) : 0) + /* argc[0] == exename */
468436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      sizeof(HChar **)*argc +                 /* argv */
469436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      sizeof(HChar **) +                      /* terminal NULL */
470436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      sizeof(HChar **)*envc +                 /* envp */
471436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      sizeof(HChar **) +                      /* terminal NULL */
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      auxsize +                               /* auxv */
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_ROUNDUP(stringsize, sizeof(Word));   /* strings (aligned) */
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) VG_(printf)("stacksize = %d\n", stacksize);
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* client_SP is the client's stack pointer */
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   client_SP = clstack_end - stacksize;
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   client_SP = VG_ROUNDDN(client_SP, 16); /* make stack 16 byte aligned */
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* base of the string table (aligned) */
482436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   stringbase = strtab = (HChar *)clstack_end
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         - VG_ROUNDUP(stringsize, sizeof(int));
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   clstack_start = VG_PGROUNDDN(client_SP);
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The max stack size */
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   clstack_max_size = VG_PGROUNDUP(clstack_max_size);
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0)
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)("stringsize=%d auxsize=%d stacksize=%d maxsize=0x%x\n"
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "clstack_start %p\n"
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "clstack_end   %p\n",
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	          stringsize, auxsize, stacksize, (Int)clstack_max_size,
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (void*)clstack_start, (void*)clstack_end);
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ==================== allocate space ==================== */
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { SizeT anon_size   = clstack_end - clstack_start + 1;
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     SizeT resvn_size  = clstack_max_size - anon_size;
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Addr  anon_start  = clstack_start;
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Addr  resvn_start = anon_start - resvn_size;
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     SizeT inner_HACK  = 0;
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Bool  ok;
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* So far we've only accounted for space requirements down to the
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        stack pointer.  If this target's ABI requires a redzone below
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        the stack pointer, we need to allocate an extra page, to
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        handle the worst case in which the stack pointer is almost at
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        the bottom of a page, and so there is insufficient room left
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        over to put the redzone in.  In this case the simple thing to
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        do is allocate an extra page, by shrinking the reservation by
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        one page and growing the anonymous area by a corresponding
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        page. */
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vg_assert(VG_STACK_REDZONE_SZB >= 0);
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vg_assert(VG_STACK_REDZONE_SZB < VKI_PAGE_SIZE);
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (VG_STACK_REDZONE_SZB > 0) {
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        vg_assert(resvn_size > VKI_PAGE_SIZE);
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        resvn_size -= VKI_PAGE_SIZE;
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        anon_start -= VKI_PAGE_SIZE;
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        anon_size += VKI_PAGE_SIZE;
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vg_assert(VG_IS_PAGE_ALIGNED(anon_size));
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vg_assert(VG_IS_PAGE_ALIGNED(resvn_size));
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vg_assert(VG_IS_PAGE_ALIGNED(anon_start));
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vg_assert(VG_IS_PAGE_ALIGNED(resvn_start));
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vg_assert(resvn_start == clstack_end + 1 - clstack_max_size);
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    ifdef ENABLE_INNER
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     inner_HACK = 1024*1024; // create 1M non-fault-extending stack
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    endif
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (0)
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        VG_(printf)("%#lx 0x%lx  %#lx 0x%lx\n",
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    resvn_start, resvn_size, anon_start, anon_size);
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* Create a shrinkable reservation followed by an anonymous
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        segment.  Together these constitute a growdown stack. */
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     res = VG_(mk_SysRes_Error)(0);
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     ok = VG_(am_create_reservation)(
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             resvn_start,
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             resvn_size -inner_HACK,
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             SmUpper,
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             anon_size +inner_HACK
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (ok) {
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* allocate a stack - mmap enough space for the stack */
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        res = VG_(am_mmap_anon_fixed_client)(
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 anon_start -inner_HACK,
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 anon_size +inner_HACK,
552436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	         info->stack_prot
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      );
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if ((!ok) || sr_isError(res)) {
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* Allocation of the stack failed.  We have to stop. */
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        VG_(printf)("valgrind: "
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "I failed to allocate space for the application's stack.\n");
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        VG_(printf)("valgrind: "
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "This may be the result of a very large --main-stacksize=\n");
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        VG_(printf)("valgrind: setting.  Cannot continue.  Sorry.\n\n");
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        VG_(exit)(0);
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vg_assert(ok);
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vg_assert(!sr_isError(res));
567436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
568436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     /* Record stack extent -- needed for stack-change code. */
569436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     VG_(clstk_base) = anon_start -inner_HACK;
570436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     VG_(clstk_end)  = VG_(clstk_base) + anon_size +inner_HACK -1;
571436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ==================== create client stack ==================== */
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ptr = (Addr*)client_SP;
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- client argc --- */
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *ptr++ = argc + (have_exename ? 1 : 0);
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- client argv --- */
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (info->interp_name) {
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ptr++ = (Addr)copy_str(&strtab, info->interp_name);
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(free)(info->interp_name);
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (info->interp_args) {
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ptr++ = (Addr)copy_str(&strtab, info->interp_args);
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(free)(info->interp_args);
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have_exename)
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ptr++ = (Addr)copy_str(&strtab, VG_(args_the_exename));
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ptr++ = (Addr)copy_str(
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       &strtab,
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       * (HChar**) VG_(indexXA)( VG_(args_for_client), i )
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     );
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *ptr++ = 0;
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- envp --- */
603436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(client_envp) = (HChar **)ptr;
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (cpp = orig_envp; cpp && *cpp; ptr++, cpp++)
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ptr = (Addr)copy_str(&strtab, *cpp);
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *ptr++ = 0;
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- auxv --- */
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   auxv = (struct auxv *)ptr;
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *client_auxv = (UInt *)auxv;
611b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(client_auxv) = (UWord *)*client_auxv;
612b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // ??? According to 'man proc', auxv is a array of unsigned long
613b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // terminated by two zeros. Why is valgrind working with UInt ?
614b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // We do not take ULong* (as ULong 8 bytes on a 32 bits),
615b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   // => we take UWord*
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   auxv[0].a_type  = AT_IGNOREPPC;
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   auxv[0].u.a_val = AT_IGNOREPPC;
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   auxv[1].a_type  = AT_IGNOREPPC;
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   auxv[1].u.a_val = AT_IGNOREPPC;
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   auxv += 2;
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (; orig_auxv->a_type != AT_NULL; auxv++, orig_auxv++) {
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* copy the entry... */
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *auxv = *orig_auxv;
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ...and fix up / examine the copy */
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch(auxv->a_type) {
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_IGNORE:
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_PHENT:
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_PAGESZ:
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_FLAGS:
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_NOTELF:
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_UID:
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_EUID:
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_GID:
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_EGID:
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_CLKTCK:
643436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#        if !defined(VGPV_arm_linux_android) \
644436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            && !defined(VGPV_x86_linux_android) \
64578c715b24ad43c879a589fb02c7c4f94304425c5Dmitriy Ivanov            && !defined(VGPV_mips32_linux_android) \
64678c715b24ad43c879a589fb02c7c4f94304425c5Dmitriy Ivanov            && !defined(VGPV_arm64_linux_android)
647b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         case AT_FPUCW: /* missing on android */
648b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#        endif
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* All these are pointerless, so we don't need to do
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               anything about them. */
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_PHDR:
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (info->phdr == 0)
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               auxv->a_type = AT_IGNORE;
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            else
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               auxv->u.a_val = info->phdr;
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_PHNUM:
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (info->phdr == 0)
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               auxv->a_type = AT_IGNORE;
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            else
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               auxv->u.a_val = info->phnum;
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_BASE:
668436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            auxv->u.a_val = info->interp_offset;
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_PLATFORM:
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_BASE_PLATFORM:
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* points to a platform description string */
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            auxv->u.a_ptr = copy_str(&strtab, orig_auxv->u.a_ptr);
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_ENTRY:
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            auxv->u.a_val = info->entry;
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_HWCAP:
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#           if defined(VGP_arm_linux)
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            { Bool has_neon = (auxv->u.a_val & VKI_HWCAP_NEON) > 0;
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              VG_(debugLog)(2, "initimg",
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               "ARM has-neon from-auxv: %s\n",
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               has_neon ? "YES" : "NO");
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              VG_(machine_arm_set_has_NEON)( has_neon );
688663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng              #define VKI_HWCAP_TLS 32768
689663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng              Bool has_tls = (auxv->u.a_val & VKI_HWCAP_TLS) > 0;
690663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng              VG_(debugLog)(2, "initimg",
691663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                               "ARM has-tls from-auxv: %s\n",
692663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                               has_tls ? "YES" : "NO");
693663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng              /* If real hw sets properly HWCAP_TLS, we might
694663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                 use this info to decide to really execute set_tls syscall
695663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                 in syswrap-arm-linux.c rather than to base this on
696663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                 conditional compilation. */
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#           endif
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_ICACHEBSIZE:
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_UCACHEBSIZE:
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#           if defined(VGP_ppc32_linux)
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* acquire cache info */
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (auxv->u.a_val > 0) {
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               VG_(machine_ppc32_set_clszB)( auxv->u.a_val );
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               VG_(debugLog)(2, "initimg",
708436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                "PPC32 icache line size %u (type %u)\n",
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                (UInt)auxv->u.a_val, (UInt)auxv->a_type );
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#           elif defined(VGP_ppc64_linux)
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* acquire cache info */
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (auxv->u.a_val > 0) {
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               VG_(machine_ppc64_set_clszB)( auxv->u.a_val );
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               VG_(debugLog)(2, "initimg",
716436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                "PPC64 icache line size %u (type %u)\n",
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                (UInt)auxv->u.a_val, (UInt)auxv->a_type );
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#           endif
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_IGNOREPPC:
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        endif
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_SECURE:
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* If this is 1, then it means that this program is
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               running suid, and therefore the dynamic linker should
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               be careful about LD_PRELOAD, etc.  However, since
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stage1 (the thing the kernel actually execve's) should
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               never be SUID, and we need LD_PRELOAD to work for the
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               client, we set AT_SECURE to 0. */
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            auxv->u.a_val = 0;
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_SYSINFO:
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Trash this, because we don't reproduce it */
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            auxv->a_type = AT_IGNORE;
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        if !defined(VGP_ppc32_linux) && !defined(VGP_ppc64_linux)
743b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         case AT_SYSINFO_EHDR: {
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Trash this, because we don't reproduce it */
745b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            const NSegment* ehdrseg = VG_(am_find_nsegment)((Addr)auxv->u.a_ptr);
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vg_assert(ehdrseg);
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(am_munmap_valgrind)(ehdrseg->start, ehdrseg->end - ehdrseg->start);
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            auxv->a_type = AT_IGNORE;
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
750b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        endif
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_RANDOM:
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* points to 16 random bytes - we need to ensure this is
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               propagated to the client as glibc will assume it is
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               present if it is built for kernel 2.6.29 or later */
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            auxv->u.a_ptr = strtab;
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(memcpy)(strtab, orig_auxv->u.a_ptr, 16);
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            strtab += 16;
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case AT_EXECFN:
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* points to the executable filename */
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            auxv->u.a_ptr = copy_str(&strtab, VG_(args_the_exename));
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* stomp out anything we don't know about */
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(debugLog)(2, "initimg",
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             "stomping auxv entry %lld\n",
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             (ULong)auxv->a_type);
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            auxv->a_type = AT_IGNORE;
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *auxv = *orig_auxv;
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(auxv->a_type == AT_NULL);
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert((strtab-stringbase) == stringsize);
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* client_SP is pointing at client's argc/argv */
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) VG_(printf)("startup SP = %#lx\n", client_SP);
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return client_SP;
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Allocate the client data segment.  It is an expandable anonymous
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mapping abutting a shrinkable reservation of size max_dseg_size.
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The data segment starts at VG_(brk_base), which is page-aligned,
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and runs up to VG_(brk_limit), which isn't. */
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void setup_client_dataseg ( SizeT max_size )
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   ok;
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes sres;
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr   anon_start  = VG_(brk_base);
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SizeT  anon_size   = VKI_PAGE_SIZE;
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr   resvn_start = anon_start + anon_size;
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SizeT  resvn_size  = max_size - anon_size;
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_PAGE_ALIGNED(anon_size));
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_PAGE_ALIGNED(resvn_size));
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_PAGE_ALIGNED(anon_start));
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_IS_PAGE_ALIGNED(resvn_start));
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Because there's been no brk activity yet: */
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(brk_base) == VG_(brk_limit));
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Try to create the data seg and associated reservation where
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(brk_base) says. */
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ok = VG_(am_create_reservation)(
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           resvn_start,
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           resvn_size,
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           SmLower,
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           anon_size
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!ok) {
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Hmm, that didn't work.  Well, let aspacem suggest an address
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         it likes better, and try again with that. */
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      anon_start = VG_(am_get_advisory_client_simple)
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      ( 0/*floating*/, anon_size+resvn_size, &ok );
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ok) {
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         resvn_start = anon_start + anon_size;
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ok = VG_(am_create_reservation)(
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 resvn_start,
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 resvn_size,
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SmLower,
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 anon_size
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              );
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (ok)
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(brk_base) = VG_(brk_limit) = anon_start;
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* that too might have failed, but if it has, we're hosed: there
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         is no Plan C. */
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(ok);
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We make the data segment (heap) executable because LinuxThreads on
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ppc32 creates trampolines in this area.  Also, on x86/Linux the data
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      segment is RWX natively, at least according to /proc/self/maps.
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Also, having a non-executable data seg would kill any program which
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tried to create code in the data seg and then run it. */
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sres = VG_(am_mmap_anon_fixed_client)(
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             anon_start,
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             anon_size,
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(!sr_isError(sres));
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sr_Res(sres) == anon_start);
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*====================================================================*/
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*=== TOP-LEVEL: VG_(setup_client_initial_image)                   ===*/
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*====================================================================*/
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Create the client's initial memory image. */
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo iicii )
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ExeInfo info;
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar** env = NULL;
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IIFinaliseImageInfo iifii;
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)( &iifii, 0, sizeof(iifii) );
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //--------------------------------------------------------------
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Load client executable, finding in $PATH if necessary
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //   p: get_helprequest_and_toolname()  [for 'exec', 'need_help']
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //   p: layout_remaining_space          [so there's space]
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //--------------------------------------------------------------
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(debugLog)(1, "initimg", "Loading client\n");
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(args_the_exename) == NULL)
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(err_missing_prog)();
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   load_client(&info, &iifii.initial_client_IP, &iifii.initial_client_TOC);
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //--------------------------------------------------------------
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Set up client's environment
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //   p: set-libdir                   [for VG_(libdir)]
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //   p: get_helprequest_and_toolname [for toolname]
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //--------------------------------------------------------------
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(debugLog)(1, "initimg", "Setup client env\n");
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   env = setup_client_env(iicii.envp, iicii.toolname);
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //--------------------------------------------------------------
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Setup client stack, eip, and VG_(client_arg[cv])
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //   p: load_client()     [for 'info']
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //   p: fix_environment() [for 'env']
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //--------------------------------------------------------------
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* When allocating space for the client stack on Linux, take
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         notice of the --main-stacksize value.  This makes it possible
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         to run programs with very large (primary) stack requirements
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         simply by specifying --main-stacksize. */
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Logic is as follows:
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         - by default, use the client's current stack rlimit
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         - if that exceeds 16M, clamp to 16M
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         - if a larger --main-stacksize value is specified, use that instead
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         - in all situations, the minimum allowed stack size is 1M
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      void* init_sp = iicii.argv - 1;
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT m1  = 1024 * 1024;
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT m16 = 16 * m1;
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT szB = (SizeT)VG_(client_rlimit_stack).rlim_cur;
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (szB < m1) szB = m1;
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (szB > m16) szB = m16;
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(clo_main_stacksize) > 0) szB = VG_(clo_main_stacksize);
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (szB < m1) szB = m1;
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      szB = VG_PGROUNDUP(szB);
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(debugLog)(1, "initimg",
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "Setup client stack: size will be %ld\n", szB);
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      iifii.clstack_max_size = szB;
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      iifii.initial_client_SP
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = setup_client_stack( init_sp, env,
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               &info, &iifii.client_auxv,
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               iicii.clstack_top, iifii.clstack_max_size );
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(free)(env);
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(debugLog)(2, "initimg",
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "Client info: "
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "initial_IP=%p initial_TOC=%p brk_base=%p\n",
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       (void*)(iifii.initial_client_IP),
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       (void*)(iifii.initial_client_TOC),
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       (void*)VG_(brk_base) );
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(debugLog)(2, "initimg",
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "Client info: "
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "initial_SP=%p max_stack_size=%ld\n",
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       (void*)(iifii.initial_client_SP),
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       (SizeT)iifii.clstack_max_size );
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //--------------------------------------------------------------
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Setup client data (brk) segment.  Initially a 1-page segment
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // which abuts a shrinkable reservation.
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //     p: load_client()     [for 'info' and hence VG_(brk_base)]
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //--------------------------------------------------------------
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT m1 = 1024 * 1024;
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT m8 = 8 * m1;
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SizeT dseg_max_size = (SizeT)VG_(client_rlimit_data).rlim_cur;
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(debugLog)(1, "initimg", "Setup client data (brk) segment\n");
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (dseg_max_size < m1) dseg_max_size = m1;
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (dseg_max_size > m8) dseg_max_size = m8;
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dseg_max_size = VG_PGROUNDUP(dseg_max_size);
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setup_client_dataseg( dseg_max_size );
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return iifii;
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*====================================================================*/
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*=== TOP-LEVEL: VG_(finalise_thread1state)                        ===*/
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*====================================================================*/
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Just before starting the client, we may need to make final
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   adjustments to its initial image.  Also we need to set up the VEX
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guest state for thread 1 (the root thread) and copy in essential
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   starting values.  This is handed the IIFinaliseImageInfo created by
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(ii_create_image).
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(ii_finalise_image)( IIFinaliseImageInfo iifii )
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadArchState* arch = &VG_(threads)[1].arch;
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* On Linux we get client_{ip/sp/toc}, and start the client with
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      all other registers zeroed. */
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux)
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(0 == sizeof(VexGuestX86State) % 16);
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Zero out the initial state, and set up the simulated FPU in a
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sane way. */
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LibVEX_GuestX86_initialise(&arch->vex);
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Zero out the shadow areas. */
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestX86State));
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestX86State));
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Put essential stuff into the new state. */
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_ESP = iifii.initial_client_SP;
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_EIP = iifii.initial_client_IP;
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* initialise %cs, %ds and %ss to point at the operating systems
992663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      default code, data and stack segments.  Also %es (see #291253). */
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   asm volatile("movw %%cs, %0" : : "m" (arch->vex.guest_CS));
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   asm volatile("movw %%ds, %0" : : "m" (arch->vex.guest_DS));
995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   asm volatile("movw %%ss, %0" : : "m" (arch->vex.guest_SS));
996663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   asm volatile("movw %%es, %0" : : "m" (arch->vex.guest_ES));
997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_linux)
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(0 == sizeof(VexGuestAMD64State) % 16);
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Zero out the initial state, and set up the simulated FPU in a
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sane way. */
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LibVEX_GuestAMD64_initialise(&arch->vex);
1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Zero out the shadow areas. */
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestAMD64State));
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestAMD64State));
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Put essential stuff into the new state. */
1010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_RSP = iifii.initial_client_SP;
1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_RIP = iifii.initial_client_IP;
1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_ppc32_linux)
1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(0 == sizeof(VexGuestPPC32State) % 16);
1015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Zero out the initial state, and set up the simulated FPU in a
1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sane way. */
1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LibVEX_GuestPPC32_initialise(&arch->vex);
1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Zero out the shadow areas. */
1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestPPC32State));
1022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestPPC32State));
1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Put essential stuff into the new state. */
1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_GPR1 = iifii.initial_client_SP;
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_CIA  = iifii.initial_client_IP;
1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_ppc64_linux)
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(0 == sizeof(VexGuestPPC64State) % 16);
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Zero out the initial state, and set up the simulated FPU in a
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sane way. */
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LibVEX_GuestPPC64_initialise(&arch->vex);
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Zero out the shadow areas. */
1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestPPC64State));
1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestPPC64State));
1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Put essential stuff into the new state. */
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_GPR1 = iifii.initial_client_SP;
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_GPR2 = iifii.initial_client_TOC;
1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_CIA  = iifii.initial_client_IP;
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1044436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  elif defined(VGP_arm_linux)
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Zero out the initial state, and set up the simulated FPU in a
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sane way. */
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LibVEX_GuestARM_initialise(&arch->vex);
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Zero out the shadow areas. */
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestARMState));
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestARMState));
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_R13  = iifii.initial_client_SP;
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_R15T = iifii.initial_client_IP;
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This is just EABI stuff. */
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FIXME jrs: what's this for?
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_R1 =  iifii.initial_client_SP;
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1060436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  elif defined(VGP_arm64_linux)
1061436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Zero out the initial state. */
1062436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   LibVEX_GuestARM64_initialise(&arch->vex);
1063436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1064436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Zero out the shadow areas. */
1065436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestARM64State));
1066436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestARM64State));
1067436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1068436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   arch->vex.guest_XSP = iifii.initial_client_SP;
1069436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   arch->vex.guest_PC  = iifii.initial_client_IP;
1070436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1071b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  elif defined(VGP_s390x_linux)
1072b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(0 == sizeof(VexGuestS390XState) % 16);
1073b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1074b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Zero out the initial state. This also sets the guest_fpc to 0, which
1075b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      is also done by the kernel for the fpc during execve. */
1076b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   LibVEX_GuestS390X_initialise(&arch->vex);
1077b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1078663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* Mark all registers as undefined ... */
1079663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memset)(&arch->vex_shadow1, 0xFF, sizeof(VexGuestS390XState));
1080663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memset)(&arch->vex_shadow2, 0x00, sizeof(VexGuestS390XState));
1081663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* ... except SP, FPC, and IA */
1082436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   arch->vex_shadow1.guest_SP = 0;
1083436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   arch->vex_shadow1.guest_fpc = 0;
1084436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   arch->vex_shadow1.guest_IA = 0;
1085b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1086b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Put essential stuff into the new state. */
1087b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   arch->vex.guest_SP = iifii.initial_client_SP;
1088b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   arch->vex.guest_IA = iifii.initial_client_IP;
1089663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* See sys_execve in <linux>/arch/s390/kernel/process.c */
1090663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   arch->vex.guest_fpc = 0;
1091663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1092663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* Tell the tool about the registers we just wrote */
1093663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_TRACK(post_reg_write, Vg_CoreStartup, /*tid*/1, VG_O_STACK_PTR, 8);
1094663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_TRACK(post_reg_write, Vg_CoreStartup, /*tid*/1, VG_O_FPC_REG,   4);
1095663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_TRACK(post_reg_write, Vg_CoreStartup, /*tid*/1, VG_O_INSTR_PTR, 8);
1096663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   return;
1097663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1098663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGP_mips32_linux)
1099663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vg_assert(0 == sizeof(VexGuestMIPS32State) % 16);
1100663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* Zero out the initial state, and set up the simulated FPU in a
1101663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      sane way. */
1102663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   LibVEX_GuestMIPS32_initialise(&arch->vex);
1103663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1104663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* Zero out the shadow areas. */
1105663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestMIPS32State));
1106663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestMIPS32State));
1107663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1108663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   arch->vex.guest_r29 = iifii.initial_client_SP;
1109663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   arch->vex.guest_PC = iifii.initial_client_IP;
1110663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   arch->vex.guest_r31 = iifii.initial_client_SP;
1111b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1112436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#   elif defined(VGP_mips64_linux)
1113436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(0 == sizeof(VexGuestMIPS64State) % 16);
1114436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Zero out the initial state, and set up the simulated FPU in a
1115436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      sane way. */
1116436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   LibVEX_GuestMIPS64_initialise(&arch->vex);
1117436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1118436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Zero out the shadow areas. */
1119436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestMIPS64State));
1120436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestMIPS64State));
1121436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1122436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   arch->vex.guest_r29 = iifii.initial_client_SP;
1123436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   arch->vex.guest_PC = iifii.initial_client_IP;
1124436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   arch->vex.guest_r31 = iifii.initial_client_SP;
1125436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Unknown platform
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Tell the tool that we just wrote to the registers. */
1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_reg_write, Vg_CoreStartup, /*tid*/1, /*offset*/0,
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             sizeof(VexGuestArchState));
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif // defined(VGO_linux)
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                              ---*/
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1140