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