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