Home | History | Annotate | Download | only in m_initimg
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- Startup: create initial process image on Darwin              ---*/
      4 /*---                                             initimg-darwin.c ---*/
      5 /*--------------------------------------------------------------------*/
      6 
      7 /*
      8    This file is part of Valgrind, a dynamic binary instrumentation
      9    framework.
     10 
     11    Copyright (C) 2000-2012 Julian Seward
     12       jseward (at) acm.org
     13 
     14    This program is free software; you can redistribute it and/or
     15    modify it under the terms of the GNU General Public License as
     16    published by the Free Software Foundation; either version 2 of the
     17    License, or (at your option) any later version.
     18 
     19    This program is distributed in the hope that it will be useful, but
     20    WITHOUT ANY WARRANTY; without even the implied warranty of
     21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     22    General Public License for more details.
     23 
     24    You should have received a copy of the GNU General Public License
     25    along with this program; if not, write to the Free Software
     26    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     27    02111-1307, USA.
     28 
     29    The GNU General Public License is contained in the file COPYING.
     30 */
     31 
     32 #if defined(VGO_darwin)
     33 
     34 #include "pub_core_basics.h"
     35 #include "pub_core_vki.h"
     36 #include "pub_core_debuglog.h"
     37 #include "pub_core_libcbase.h"
     38 #include "pub_core_libcassert.h"
     39 #include "pub_core_libcfile.h"
     40 #include "pub_core_libcproc.h"
     41 #include "pub_core_libcprint.h"
     42 #include "pub_core_xarray.h"
     43 #include "pub_core_clientstate.h"
     44 #include "pub_core_aspacemgr.h"
     45 #include "pub_core_mallocfree.h"
     46 #include "pub_core_machine.h"
     47 #include "pub_core_ume.h"
     48 #include "pub_core_options.h"
     49 #include "pub_core_tooliface.h"       /* VG_TRACK */
     50 #include "pub_core_libcsetjmp.h"      // to keep _threadstate.h happy
     51 #include "pub_core_threadstate.h"     /* ThreadArchState */
     52 #include "priv_initimg_pathscan.h"
     53 #include "pub_core_initimg.h"         /* self */
     54 
     55 
     56 /*====================================================================*/
     57 /*=== Loading the client                                           ===*/
     58 /*====================================================================*/
     59 
     60 /* Load the client whose name is VG_(argv_the_exename). */
     61 
     62 static void load_client ( /*OUT*/ExeInfo* info,
     63                           /*OUT*/Addr*    client_ip)
     64 {
     65    HChar* exe_name;
     66    Int    ret;
     67    SysRes res;
     68 
     69    vg_assert( VG_(args_the_exename) != NULL);
     70    exe_name = ML_(find_executable)( VG_(args_the_exename) );
     71 
     72    if (!exe_name) {
     73       VG_(printf)("valgrind: %s: command not found\n", VG_(args_the_exename));
     74       VG_(exit)(127);      // 127 is Posix NOTFOUND
     75    }
     76 
     77    VG_(memset)(info, 0, sizeof(*info));
     78    ret = VG_(do_exec)(exe_name, info);
     79 
     80    // The client was successfully loaded!  Continue.
     81 
     82    /* Get hold of a file descriptor which refers to the client
     83       executable.  This is needed for attaching to GDB. */
     84    res = VG_(open)(exe_name, VKI_O_RDONLY, VKI_S_IRUSR);
     85    if (!sr_isError(res))
     86       VG_(cl_exec_fd) = sr_Res(res);
     87 
     88    /* Copy necessary bits of 'info' that were filled in */
     89    *client_ip  = info->init_ip;
     90 }
     91 
     92 
     93 /*====================================================================*/
     94 /*=== Setting up the client's environment                          ===*/
     95 /*====================================================================*/
     96 
     97 /* Prepare the client's environment.  This is basically a copy of our
     98    environment, except:
     99 
    100      DYLD_INSERT_LIBRARIES=$VALGRIND_LIB/vgpreload_core-PLATFORM.so:
    101                 ($VALGRIND_LIB/vgpreload_TOOL-PLATFORM.so:)?
    102                 DYLD_INSERT_LIBRARIES
    103 
    104    If this is missing, then it is added.
    105 
    106    Also, remove any binding for VALGRIND_LAUNCHER=.  The client should
    107    not be able to see this.
    108 
    109    Also, add DYLD_SHARED_REGION=avoid, because V doesn't know how
    110    to process the dyld shared cache file.
    111 
    112    Also, change VYLD_* (mangled by launcher) back to DYLD_*.
    113 
    114    If this needs to handle any more variables it should be hacked
    115    into something table driven.  The copy is VG_(malloc)'d space.
    116 */
    117 static HChar** setup_client_env ( HChar** origenv, const HChar* toolname)
    118 {
    119    HChar* preload_core    = "vgpreload_core";
    120    HChar* ld_preload      = "DYLD_INSERT_LIBRARIES=";
    121    HChar* dyld_cache      = "DYLD_SHARED_REGION=";
    122    HChar* dyld_cache_value= "avoid";
    123    HChar* v_launcher      = VALGRIND_LAUNCHER "=";
    124    Int    ld_preload_len  = VG_(strlen)( ld_preload );
    125    Int    dyld_cache_len  = VG_(strlen)( dyld_cache );
    126    Int    v_launcher_len  = VG_(strlen)( v_launcher );
    127    Bool   ld_preload_done = False;
    128    Bool   dyld_cache_done = False;
    129    Int    vglib_len       = VG_(strlen)(VG_(libdir));
    130 
    131    HChar** cpp;
    132    HChar** ret;
    133    HChar*  preload_tool_path;
    134    Int     envc, i;
    135 
    136    /* Alloc space for the vgpreload_core.so path and vgpreload_<tool>.so
    137       paths.  We might not need the space for vgpreload_<tool>.so, but it
    138       doesn't hurt to over-allocate briefly.  The 16s are just cautious
    139       slop. */
    140    Int preload_core_path_len = vglib_len + sizeof(preload_core)
    141                                          + sizeof(VG_PLATFORM) + 16;
    142    Int preload_tool_path_len = vglib_len + VG_(strlen)(toolname)
    143                                          + sizeof(VG_PLATFORM) + 16;
    144    Int preload_string_len    = preload_core_path_len + preload_tool_path_len;
    145    HChar* preload_string     = VG_(malloc)("initimg-darwin.sce.1", preload_string_len);
    146    vg_assert(preload_string);
    147 
    148    /* Determine if there's a vgpreload_<tool>_<platform>.so file, and setup
    149       preload_string. */
    150    preload_tool_path = VG_(malloc)("initimg-darwin.sce.2", preload_tool_path_len);
    151    vg_assert(preload_tool_path);
    152    VG_(snprintf)(preload_tool_path, preload_tool_path_len,
    153                  "%s/vgpreload_%s-%s.so", VG_(libdir), toolname, VG_PLATFORM);
    154    if (VG_(access)(preload_tool_path, True/*r*/, False/*w*/, False/*x*/) == 0) {
    155       VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so:%s",
    156                     VG_(libdir), preload_core, VG_PLATFORM, preload_tool_path);
    157    } else {
    158       VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so",
    159                     VG_(libdir), preload_core, VG_PLATFORM);
    160    }
    161    VG_(free)(preload_tool_path);
    162 
    163    VG_(debugLog)(2, "initimg", "preload_string:\n");
    164    VG_(debugLog)(2, "initimg", "  \"%s\"\n", preload_string);
    165 
    166    /* Count the original size of the env */
    167    envc = 0;
    168    for (cpp = origenv; cpp && *cpp; cpp++)
    169       envc++;
    170 
    171    /* Allocate a new space */
    172    ret = VG_(malloc) ("initimg-darwin.sce.3",
    173                       sizeof(HChar *) * (envc+2+1)); /* 2 new entries + NULL */
    174    vg_assert(ret);
    175 
    176    /* copy it over */
    177    for (cpp = ret; *origenv; )
    178       *cpp++ = *origenv++;
    179    *cpp = NULL;
    180 
    181    vg_assert(envc == (cpp - ret));
    182 
    183    /* Walk over the new environment, mashing as we go */
    184    for (cpp = ret; cpp && *cpp; cpp++) {
    185       if (VG_(memcmp)(*cpp, ld_preload, ld_preload_len) == 0) {
    186          Int len = VG_(strlen)(*cpp) + preload_string_len;
    187          HChar *cp = VG_(malloc)("initimg-darwin.sce.4", len);
    188          vg_assert(cp);
    189 
    190          VG_(snprintf)(cp, len, "%s%s:%s",
    191                        ld_preload, preload_string, (*cpp)+ld_preload_len);
    192 
    193          *cpp = cp;
    194 
    195          ld_preload_done = True;
    196       }
    197       if (VG_(memcmp)(*cpp, dyld_cache, dyld_cache_len) == 0) {
    198          Int len = dyld_cache_len + VG_(strlen)(dyld_cache_value) + 1;
    199          HChar *cp = VG_(malloc)("initimg-darwin.sce.4.2", len);
    200          vg_assert(cp);
    201 
    202          VG_(snprintf)(cp, len, "%s%s", dyld_cache, dyld_cache_value);
    203 
    204          *cpp = cp;
    205 
    206          ld_preload_done = True;
    207       }
    208    }
    209 
    210    /* Add the missing bits */
    211    if (!ld_preload_done) {
    212       Int len = ld_preload_len + preload_string_len;
    213       HChar *cp = VG_(malloc) ("initimg-darwin.sce.5", len);
    214       vg_assert(cp);
    215 
    216       VG_(snprintf)(cp, len, "%s%s", ld_preload, preload_string);
    217 
    218       ret[envc++] = cp;
    219    }
    220    if (!dyld_cache_done) {
    221       Int len = dyld_cache_len + VG_(strlen)(dyld_cache_value) + 1;
    222       HChar *cp = VG_(malloc) ("initimg-darwin.sce.5.2", len);
    223       vg_assert(cp);
    224 
    225       VG_(snprintf)(cp, len, "%s%s", dyld_cache, dyld_cache_value);
    226 
    227       ret[envc++] = cp;
    228    }
    229 
    230 
    231    /* ret[0 .. envc-1] is live now. */
    232    /* Find and remove a binding for VALGRIND_LAUNCHER. */
    233    for (i = 0; i < envc; i++)
    234       if (0 == VG_(memcmp)(ret[i], v_launcher, v_launcher_len))
    235          break;
    236 
    237    if (i < envc) {
    238       for (; i < envc-1; i++)
    239          ret[i] = ret[i+1];
    240       envc--;
    241    }
    242 
    243    /* Change VYLD_ to DYLD */
    244    for (i = 0; i < envc; i++) {
    245       if (0 == VG_(strncmp)(ret[i], "VYLD_", 5)) {
    246          ret[i][0] = 'D';
    247       }
    248    }
    249 
    250 
    251    VG_(free)(preload_string);
    252    ret[envc] = NULL;
    253    return ret;
    254 }
    255 
    256 
    257 /*====================================================================*/
    258 /*=== Setting up the client's stack                                ===*/
    259 /*====================================================================*/
    260 
    261 /* Add a string onto the string table, and return its address */
    262 static char *copy_str(char **tab, const char *str)
    263 {
    264    char *cp = *tab;
    265    char *orig = cp;
    266 
    267    while(*str)
    268       *cp++ = *str++;
    269    *cp++ = '\0';
    270 
    271    if (0)
    272       VG_(printf)("copied %p \"%s\" len %lld\n", orig, orig, (Long)(cp-orig));
    273 
    274    *tab = cp;
    275 
    276    return orig;
    277 }
    278 
    279 
    280 /* ----------------------------------------------------------------
    281 
    282    This sets up the client's initial stack, containing the args,
    283    environment and aux vector.
    284 
    285    The format of the stack on Darwin is:
    286 
    287    higher address +-----------------+ <- clstack_end
    288                   |                 |
    289                   : string table    :
    290                   |                 |
    291                   +-----------------+
    292                   | NULL            |
    293                   +-----------------+
    294                   | executable_path | (first arg to execve())
    295                   +-----------------+
    296                   | NULL            |
    297                   -                 -
    298                   | envp            |
    299                   +-----------------+
    300                   | NULL            |
    301                   -                 -
    302                   | argv            |
    303                   +-----------------+
    304                   | argc            |
    305                   +-----------------+
    306                   | mach_header *   | (dynamic only)
    307    lower address  +-----------------+ <- sp
    308                   | undefined       |
    309                   :                 :
    310 
    311    Allocate and create the initial client stack.  It is allocated down
    312    from clstack_end, which was previously determined by the address
    313    space manager.  The returned value is the SP value for the client.
    314 
    315    ---------------------------------------------------------------- */
    316 
    317 static
    318 Addr setup_client_stack( void*  init_sp,
    319                          char** orig_envp,
    320                          const ExeInfo* info,
    321                          Addr   clstack_end,
    322                          SizeT  clstack_max_size )
    323 {
    324    char **cpp;
    325    char *strtab;		/* string table */
    326    char *stringbase;
    327    Addr *ptr;
    328    unsigned stringsize;		/* total size of strings in bytes */
    329    unsigned auxsize;		/* total size of auxv in bytes */
    330    Int argc;			/* total argc */
    331    Int envc;			/* total number of env vars */
    332    unsigned stacksize;		/* total client stack size */
    333    Addr client_SP;	        /* client stack base (initial SP) */
    334    Addr clstack_start;
    335    Int i;
    336    Bool have_exename;
    337 
    338    vg_assert(VG_IS_PAGE_ALIGNED(clstack_end+1));
    339    vg_assert( VG_(args_for_client) );
    340 
    341    /* ==================== compute sizes ==================== */
    342 
    343    /* first of all, work out how big the client stack will be */
    344    stringsize   = 0;
    345    auxsize = 0;
    346    have_exename = VG_(args_the_exename) != NULL;
    347 
    348    /* paste on the extra args if the loader needs them (ie, the #!
    349       interpreter and its argument) */
    350    argc = 0;
    351    if (info->interp_name != NULL) {
    352       argc++;
    353       stringsize += VG_(strlen)(info->interp_name) + 1;
    354    }
    355    if (info->interp_args != NULL) {
    356       argc++;
    357       stringsize += VG_(strlen)(info->interp_args) + 1;
    358    }
    359 
    360    /* now scan the args we're given... */
    361    if (have_exename)
    362       stringsize += VG_(strlen)( VG_(args_the_exename) ) + 1;
    363 
    364    for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
    365       argc++;
    366       stringsize += VG_(strlen)( * (HChar**)
    367                                    VG_(indexXA)( VG_(args_for_client), i ))
    368                     + 1;
    369    }
    370 
    371    /* ...and the environment */
    372    envc = 0;
    373    for (cpp = orig_envp; cpp && *cpp; cpp++) {
    374       envc++;
    375       stringsize += VG_(strlen)(*cpp) + 1;
    376    }
    377 
    378    /* Darwin executable_path + NULL */
    379    auxsize += 2 * sizeof(Word);
    380    if (info->executable_path) {
    381        stringsize += 1 + VG_(strlen)(info->executable_path);
    382    }
    383 
    384    /* Darwin mach_header */
    385    if (info->dynamic) auxsize += sizeof(Word);
    386 
    387    /* OK, now we know how big the client stack is */
    388    stacksize =
    389       sizeof(Word) +                          /* argc */
    390       (have_exename ? sizeof(char **) : 0) +  /* argc[0] == exename */
    391       sizeof(char **)*argc +                  /* argv */
    392       sizeof(char **) +	                      /* terminal NULL */
    393       sizeof(char **)*envc +                  /* envp */
    394       sizeof(char **) +	                      /* terminal NULL */
    395       auxsize +                               /* auxv */
    396       VG_ROUNDUP(stringsize, sizeof(Word));   /* strings (aligned) */
    397 
    398    if (0) VG_(printf)("stacksize = %d\n", stacksize);
    399 
    400    /* client_SP is the client's stack pointer */
    401    client_SP = clstack_end - stacksize;
    402    client_SP = VG_ROUNDDN(client_SP, 32); /* make stack 32 byte aligned */
    403 
    404    /* base of the string table (aligned) */
    405    stringbase = strtab = (char *)clstack_end
    406                          - VG_ROUNDUP(stringsize, sizeof(int));
    407 
    408    /* The max stack size */
    409    clstack_max_size = VG_PGROUNDUP(clstack_max_size);
    410 
    411    /* Darwin stack is chosen by the ume loader */
    412    clstack_start = clstack_end - clstack_max_size;
    413 
    414    /* Record stack extent -- needed for stack-change code. */
    415    /* GrP fixme really? */
    416    VG_(clstk_base) = clstack_start;
    417    VG_(clstk_end)  = clstack_end;
    418 
    419    if (0)
    420       VG_(printf)("stringsize=%d auxsize=%d stacksize=%d maxsize=0x%x\n"
    421                   "clstack_start %p\n"
    422                   "clstack_end   %p\n",
    423 	          stringsize, auxsize, stacksize, (Int)clstack_max_size,
    424                   (void*)clstack_start, (void*)clstack_end);
    425 
    426    /* ==================== allocate space ==================== */
    427 
    428    /* Stack was allocated by the ume loader. */
    429 
    430    /* ==================== create client stack ==================== */
    431 
    432    ptr = (Addr*)client_SP;
    433 
    434    /* --- mach_header --- */
    435    if (info->dynamic) *ptr++ = info->text;
    436 
    437    /* --- client argc --- */
    438    *ptr++ = (Addr)(argc + (have_exename ? 1 : 0));
    439 
    440    /* --- client argv --- */
    441    if (info->interp_name) {
    442       *ptr++ = (Addr)copy_str(&strtab, info->interp_name);
    443       VG_(free)(info->interp_name);
    444    }
    445    if (info->interp_args) {
    446       *ptr++ = (Addr)copy_str(&strtab, info->interp_args);
    447       VG_(free)(info->interp_args);
    448    }
    449 
    450    if (have_exename)
    451       *ptr++ = (Addr)copy_str(&strtab, VG_(args_the_exename));
    452 
    453    for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
    454       *ptr++ = (Addr)copy_str(
    455                        &strtab,
    456                        * (HChar**) VG_(indexXA)( VG_(args_for_client), i )
    457                      );
    458    }
    459    *ptr++ = 0;
    460 
    461    /* --- envp --- */
    462    VG_(client_envp) = (Char **)ptr;
    463    for (cpp = orig_envp; cpp && *cpp; ptr++, cpp++)
    464       *ptr = (Addr)copy_str(&strtab, *cpp);
    465    *ptr++ = 0;
    466 
    467    /* --- executable_path + NULL --- */
    468    if (info->executable_path)
    469        *ptr++ = (Addr)copy_str(&strtab, info->executable_path);
    470    else
    471        *ptr++ = 0;
    472    *ptr++ = 0;
    473 
    474    vg_assert((strtab-stringbase) == stringsize);
    475 
    476    /* client_SP is pointing at client's argc/argv */
    477 
    478    if (0) VG_(printf)("startup SP = %#lx\n", client_SP);
    479    return client_SP;
    480 }
    481 
    482 
    483 /*====================================================================*/
    484 /*=== Record system memory regions                                 ===*/
    485 /*====================================================================*/
    486 
    487 static void record_system_memory(void)
    488 {
    489    /* Tell aspacem where the client's kernel commpage is */
    490 #if defined(VGA_amd64)
    491    /* commpage 0x7fff:ffe00000+ - not in vm_region */
    492    // GrP fixme check again
    493    VG_(am_notify_client_mmap)(0x7fffffe00000, 0x7ffffffff000-0x7fffffe00000,
    494                               VKI_PROT_READ|VKI_PROT_EXEC, 0, -1, 0);
    495 
    496 #elif defined(VGA_x86)
    497    /* commpage 0xfffec000+ - not in vm_region */
    498    // GrP fixme check again
    499    VG_(am_notify_client_mmap)(0xfffec000, 0xfffff000-0xfffec000,
    500                               VKI_PROT_READ|VKI_PROT_EXEC, 0, -1, 0);
    501 
    502 #else
    503 #  error unknown architecture
    504 #endif
    505 }
    506 
    507 
    508 /*====================================================================*/
    509 /*=== TOP-LEVEL: VG_(ii_create_image)                              ===*/
    510 /*====================================================================*/
    511 
    512 /* Create the client's initial memory image. */
    513 IIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo iicii )
    514 {
    515    ExeInfo info;
    516    HChar** env = NULL;
    517 
    518    IIFinaliseImageInfo iifii;
    519    VG_(memset)( &iifii, 0, sizeof(iifii) );
    520 
    521    //--------------------------------------------------------------
    522    // Load client executable, finding in $PATH if necessary
    523    //   p: get_helprequest_and_toolname()  [for 'exec', 'need_help']
    524    //   p: layout_remaining_space          [so there's space]
    525    //--------------------------------------------------------------
    526    VG_(debugLog)(1, "initimg", "Loading client\n");
    527 
    528    if (VG_(args_the_exename) == NULL)
    529       VG_(err_missing_prog)();
    530 
    531    load_client(&info, &iifii.initial_client_IP);
    532 
    533    //--------------------------------------------------------------
    534    // Set up client's environment
    535    //   p: set-libdir                   [for VG_(libdir)]
    536    //   p: get_helprequest_and_toolname [for toolname]
    537    //--------------------------------------------------------------
    538    VG_(debugLog)(1, "initimg", "Setup client env\n");
    539    env = setup_client_env(iicii.envp, iicii.toolname);
    540 
    541    //--------------------------------------------------------------
    542    // Setup client stack, eip, and VG_(client_arg[cv])
    543    //   p: load_client()     [for 'info']
    544    //   p: fix_environment() [for 'env']
    545    //--------------------------------------------------------------
    546    iicii.clstack_top = info.stack_end - 1;
    547    iifii.clstack_max_size = info.stack_end - info.stack_start;
    548 
    549    iifii.initial_client_SP =
    550        setup_client_stack( iicii.argv - 1, env, &info,
    551                            iicii.clstack_top, iifii.clstack_max_size );
    552 
    553    VG_(free)(env);
    554 
    555    VG_(debugLog)(2, "initimg",
    556                  "Client info: "
    557                  "initial_IP=%p initial_SP=%p stack=%p..%p\n",
    558                  (void*)(iifii.initial_client_IP),
    559                  (void*)(iifii.initial_client_SP),
    560                  (void*)(info.stack_start),
    561                  (void*)(info.stack_end));
    562 
    563 
    564    // Tell aspacem about commpage, etc
    565    record_system_memory();
    566 
    567    return iifii;
    568 }
    569 
    570 
    571 /*====================================================================*/
    572 /*=== TOP-LEVEL: VG_(ii_finalise_image)                            ===*/
    573 /*====================================================================*/
    574 
    575 /* Just before starting the client, we may need to make final
    576    adjustments to its initial image.  Also we need to set up the VEX
    577    guest state for thread 1 (the root thread) and copy in essential
    578    starting values.  This is handed the IIFinaliseImageInfo created by
    579    VG_(ii_create_image).
    580 */
    581 void VG_(ii_finalise_image)( IIFinaliseImageInfo iifii )
    582 {
    583    ThreadArchState* arch = &VG_(threads)[1].arch;
    584 
    585    /* GrP fixme doesn't handle all registers from LC_THREAD or LC_UNIXTHREAD */
    586 
    587 #  if defined(VGP_x86_darwin)
    588    vg_assert(0 == sizeof(VexGuestX86State) % 16);
    589 
    590    /* Zero out the initial state, and set up the simulated FPU in a
    591       sane way. */
    592    LibVEX_GuestX86_initialise(&arch->vex);
    593 
    594    /* Zero out the shadow areas. */
    595    VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestX86State));
    596    VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestX86State));
    597 
    598    /* Put essential stuff into the new state. */
    599    arch->vex.guest_ESP = iifii.initial_client_SP;
    600    arch->vex.guest_EIP = iifii.initial_client_IP;
    601 
    602 #  elif defined(VGP_amd64_darwin)
    603    vg_assert(0 == sizeof(VexGuestAMD64State) % 16);
    604 
    605    /* Zero out the initial state, and set up the simulated FPU in a
    606       sane way. */
    607    LibVEX_GuestAMD64_initialise(&arch->vex);
    608 
    609    /* Zero out the shadow areas. */
    610    VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestAMD64State));
    611    VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestAMD64State));
    612 
    613    /* Put essential stuff into the new state. */
    614    arch->vex.guest_RSP = iifii.initial_client_SP;
    615    arch->vex.guest_RIP = iifii.initial_client_IP;
    616 
    617 #  else
    618 #    error Unknown platform
    619 #  endif
    620 
    621    /* Tell the tool that we just wrote to the registers. */
    622    VG_TRACK( post_reg_write, Vg_CoreStartup, /*tid*/1, /*offset*/0,
    623              sizeof(VexGuestArchState));
    624 }
    625 
    626 #endif // defined(VGO_darwin)
    627 
    628 /*--------------------------------------------------------------------*/
    629 /*--- end                                                          ---*/
    630 /*--------------------------------------------------------------------*/
    631