2 /*--------------------------------------------------------------------*/
3 /*--- Startup: create initial process image on Darwin ---*/
4 /*--- initimg-darwin.c ---*/
5 /*--------------------------------------------------------------------*/
8 This file is part of Valgrind, a dynamic binary instrumentation
11 Copyright (C) 2000-2017 Julian Seward
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.
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.
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
29 The GNU General Public License is contained in the file COPYING.
32 #if defined(VGO_darwin)
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 */
55 /*====================================================================*/
56 /*=== Loading the client ===*/
57 /*====================================================================*/
59 /* Load the client whose name is VG_(argv_the_exename). */
61 static void load_client ( /*OUT*/ExeInfo
* info
,
62 /*OUT*/Addr
* client_ip
)
64 const HChar
* exe_name
;
68 vg_assert( VG_(args_the_exename
) != NULL
);
69 exe_name
= ML_(find_executable
)( VG_(args_the_exename
) );
72 VG_(printf
)("valgrind: %s: command not found\n", VG_(args_the_exename
));
73 VG_(exit
)(127); // 127 is Posix NOTFOUND
76 VG_(memset
)(info
, 0, sizeof(*info
));
77 ret
= VG_(do_exec
)(exe_name
, info
);
79 // The client was successfully loaded! Continue.
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
);
85 VG_(cl_exec_fd
) = sr_Res(res
);
87 /* Copy necessary bits of 'info' that were filled in */
88 *client_ip
= info
->init_ip
;
92 /*====================================================================*/
93 /*=== Setting up the client's environment ===*/
94 /*====================================================================*/
96 /* Prepare the client's environment. This is basically a copy of our
99 DYLD_INSERT_LIBRARIES=$VALGRIND_LIB/vgpreload_core-PLATFORM.so:
100 ($VALGRIND_LIB/vgpreload_TOOL-PLATFORM.so:)?
101 DYLD_INSERT_LIBRARIES
103 If this is missing, then it is added.
105 Also, remove any binding for VALGRIND_LAUNCHER=. The client should
106 not be able to see this.
108 Also, add DYLD_SHARED_REGION=avoid, because V doesn't know how
109 to process the dyld shared cache file.
111 Also, change VYLD_* (mangled by launcher) back to DYLD_*.
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.
116 static HChar
** setup_client_env ( HChar
** origenv
, const HChar
* toolname
)
118 const HChar
* preload_core
= "vgpreload_core";
119 const HChar
* ld_preload
= "DYLD_INSERT_LIBRARIES=";
120 const HChar
* dyld_cache
= "DYLD_SHARED_REGION=";
121 const HChar
* dyld_cache_value
= "avoid";
122 const 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
));
132 HChar
* preload_tool_path
;
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
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
);
146 /* Determine if there's a vgpreload_<tool>_<platform>.so file, and setup
148 preload_tool_path
= VG_(malloc
)("initimg-darwin.sce.2", preload_tool_path_len
);
149 VG_(snprintf
)(preload_tool_path
, preload_tool_path_len
,
150 "%s/vgpreload_%s-%s.so", VG_(libdir
), toolname
, VG_PLATFORM
);
151 if (VG_(access
)(preload_tool_path
, True
/*r*/, False
/*w*/, False
/*x*/) == 0) {
152 VG_(snprintf
)(preload_string
, preload_string_len
, "%s/%s-%s.so:%s",
153 VG_(libdir
), preload_core
, VG_PLATFORM
, preload_tool_path
);
155 VG_(snprintf
)(preload_string
, preload_string_len
, "%s/%s-%s.so",
156 VG_(libdir
), preload_core
, VG_PLATFORM
);
158 VG_(free
)(preload_tool_path
);
160 VG_(debugLog
)(2, "initimg", "preload_string:\n");
161 VG_(debugLog
)(2, "initimg", " \"%s\"\n", preload_string
);
163 /* Count the original size of the env */
165 for (cpp
= origenv
; cpp
&& *cpp
; cpp
++)
168 /* Allocate a new space */
169 ret
= VG_(malloc
) ("initimg-darwin.sce.3",
170 sizeof(HChar
*) * (envc
+2+1)); /* 2 new entries + NULL */
173 for (cpp
= ret
; *origenv
; )
177 vg_assert(envc
== (cpp
- ret
));
179 /* Walk over the new environment, mashing as we go */
180 for (cpp
= ret
; cpp
&& *cpp
; cpp
++) {
181 if (VG_(memcmp
)(*cpp
, ld_preload
, ld_preload_len
) == 0) {
182 Int len
= VG_(strlen
)(*cpp
) + preload_string_len
;
183 HChar
*cp
= VG_(malloc
)("initimg-darwin.sce.4", len
);
185 VG_(snprintf
)(cp
, len
, "%s%s:%s",
186 ld_preload
, preload_string
, (*cpp
)+ld_preload_len
);
190 ld_preload_done
= True
;
192 if (VG_(memcmp
)(*cpp
, dyld_cache
, dyld_cache_len
) == 0) {
193 Int len
= dyld_cache_len
+ VG_(strlen
)(dyld_cache_value
) + 1;
194 HChar
*cp
= VG_(malloc
)("initimg-darwin.sce.4.2", len
);
196 VG_(snprintf
)(cp
, len
, "%s%s", dyld_cache
, dyld_cache_value
);
200 ld_preload_done
= True
;
204 /* Add the missing bits */
205 if (!ld_preload_done
) {
206 Int len
= ld_preload_len
+ preload_string_len
;
207 HChar
*cp
= VG_(malloc
) ("initimg-darwin.sce.5", len
);
209 VG_(snprintf
)(cp
, len
, "%s%s", ld_preload
, preload_string
);
213 if (!dyld_cache_done
) {
214 Int len
= dyld_cache_len
+ VG_(strlen
)(dyld_cache_value
) + 1;
215 HChar
*cp
= VG_(malloc
) ("initimg-darwin.sce.5.2", len
);
217 VG_(snprintf
)(cp
, len
, "%s%s", dyld_cache
, dyld_cache_value
);
223 /* ret[0 .. envc-1] is live now. */
224 /* Find and remove a binding for VALGRIND_LAUNCHER. */
225 for (i
= 0; i
< envc
; i
++)
226 if (0 == VG_(memcmp
)(ret
[i
], v_launcher
, v_launcher_len
))
230 for (; i
< envc
-1; i
++)
235 /* Change VYLD_ to DYLD */
236 for (i
= 0; i
< envc
; i
++) {
237 if (0 == VG_(strncmp
)(ret
[i
], "VYLD_", 5)) {
243 VG_(free
)(preload_string
);
249 /*====================================================================*/
250 /*=== Setting up the client's stack ===*/
251 /*====================================================================*/
253 /* Add a string onto the string table, and return its address */
254 static HChar
*copy_str(HChar
**tab
, const HChar
*str
)
264 VG_(printf
)("copied %p \"%s\" len %lld\n", orig
, orig
, (Long
)(cp
-orig
));
272 /* ----------------------------------------------------------------
274 This sets up the client's initial stack, containing the args,
275 environment and aux vector.
277 The format of the stack on Darwin is:
279 higher address +-----------------+ <- clstack_end
286 | executable_path | (first arg to execve())
298 | mach_header * | (dynamic only)
299 lower address +-----------------+ <- sp
303 Allocate and create the initial client stack. It is allocated down
304 from clstack_end, which was previously determined by the address
305 space manager. The returned value is the SP value for the client.
307 ---------------------------------------------------------------- */
310 Addr
setup_client_stack( void* init_sp
,
314 SizeT clstack_max_size
,
315 const VexArchInfo
* vex_archinfo
)
318 HChar
*strtab
; /* string table */
321 unsigned stringsize
; /* total size of strings in bytes */
322 unsigned auxsize
; /* total size of auxv in bytes */
323 Int argc
; /* total argc */
324 Int envc
; /* total number of env vars */
325 unsigned stacksize
; /* total client stack size */
326 Addr client_SP
; /* client stack base (initial SP) */
330 vg_assert(VG_IS_PAGE_ALIGNED(clstack_end
+1));
331 vg_assert( VG_(args_for_client
) );
333 /* ==================== compute sizes ==================== */
335 /* first of all, work out how big the client stack will be */
339 /* paste on the extra args if the loader needs them (ie, the #!
340 interpreter and its argument) */
342 if (info
->interp_name
!= NULL
) {
344 stringsize
+= VG_(strlen
)(info
->interp_name
) + 1;
346 if (info
->interp_args
!= NULL
) {
348 stringsize
+= VG_(strlen
)(info
->interp_args
) + 1;
351 /* now scan the args we're given... */
352 stringsize
+= VG_(strlen
)( VG_(args_the_exename
) ) + 1;
354 for (i
= 0; i
< VG_(sizeXA
)( VG_(args_for_client
) ); i
++) {
356 stringsize
+= VG_(strlen
)( * (HChar
**)
357 VG_(indexXA
)( VG_(args_for_client
), i
))
361 /* ...and the environment */
363 for (cpp
= orig_envp
; cpp
&& *cpp
; cpp
++) {
365 stringsize
+= VG_(strlen
)(*cpp
) + 1;
368 /* Darwin executable_path + NULL */
369 auxsize
+= 2 * sizeof(Word
);
370 if (info
->executable_path
) {
371 stringsize
+= 1 + VG_(strlen
)(info
->executable_path
);
374 /* Darwin mach_header */
375 if (info
->dynamic
) auxsize
+= sizeof(Word
);
377 /* OK, now we know how big the client stack is */
379 sizeof(Word
) + /* argc */
380 sizeof(HChar
**) + /* argc[0] == exename */
381 sizeof(HChar
**)*argc
+ /* argv */
382 sizeof(HChar
**) + /* terminal NULL */
383 sizeof(HChar
**)*envc
+ /* envp */
384 sizeof(HChar
**) + /* terminal NULL */
386 VG_ROUNDUP(stringsize
, sizeof(Word
)); /* strings (aligned) */
388 if (0) VG_(printf
)("stacksize = %d\n", stacksize
);
390 /* client_SP is the client's stack pointer */
391 client_SP
= clstack_end
+ 1 - stacksize
;
392 client_SP
= VG_ROUNDDN(client_SP
, 32); /* make stack 32 byte aligned */
394 /* base of the string table (aligned) */
395 stringbase
= strtab
= (HChar
*)clstack_end
396 - VG_ROUNDUP(stringsize
, sizeof(int));
398 /* The max stack size */
399 clstack_max_size
= VG_PGROUNDUP(clstack_max_size
);
401 /* Darwin stack is chosen by the ume loader */
402 clstack_start
= clstack_end
+ 1 - clstack_max_size
;
404 /* Record stack extent -- needed for stack-change code. */
405 /* GrP fixme really? */
406 VG_(clstk_start_base
) = clstack_start
;
407 VG_(clstk_end
) = clstack_end
;
410 VG_(printf
)("stringsize=%d auxsize=%d stacksize=%d maxsize=0x%x\n"
413 stringsize
, auxsize
, stacksize
, (Int
)clstack_max_size
,
414 (void*)clstack_start
, (void*)clstack_end
);
416 /* ==================== allocate space ==================== */
418 /* Stack was allocated by the ume loader. */
420 /* ==================== create client stack ==================== */
422 ptr
= (Addr
*)client_SP
;
424 /* --- mach_header --- */
425 if (info
->dynamic
) *ptr
++ = info
->text
;
427 /* --- client argc --- */
428 *ptr
++ = (Addr
)(argc
+ 1);
430 /* --- client argv --- */
431 if (info
->interp_name
)
432 *ptr
++ = (Addr
)copy_str(&strtab
, info
->interp_name
);
433 if (info
->interp_args
)
434 *ptr
++ = (Addr
)copy_str(&strtab
, info
->interp_args
);
436 *ptr
++ = (Addr
)copy_str(&strtab
, VG_(args_the_exename
));
438 for (i
= 0; i
< VG_(sizeXA
)( VG_(args_for_client
) ); i
++) {
439 *ptr
++ = (Addr
)copy_str(
441 * (HChar
**) VG_(indexXA
)( VG_(args_for_client
), i
)
447 VG_(client_envp
) = (HChar
**)ptr
;
448 for (cpp
= orig_envp
; cpp
&& *cpp
; ptr
++, cpp
++)
449 *ptr
= (Addr
)copy_str(&strtab
, *cpp
);
452 /* --- executable_path + NULL --- */
453 if (info
->executable_path
)
454 *ptr
++ = (Addr
)copy_str(&strtab
, info
->executable_path
);
459 vg_assert((strtab
-stringbase
) == stringsize
);
461 /* client_SP is pointing at client's argc/argv */
463 if (0) VG_(printf
)("startup SP = %#lx\n", client_SP
);
468 /*====================================================================*/
469 /*=== Record system memory regions ===*/
470 /*====================================================================*/
472 static void record_system_memory(void)
474 /* JRS 2014-Jul-08: this messes up the sync checker, because the
475 information that the kernel gives us doesn't include anything
476 about the commpage mapping. This functionality has therefore
477 been moved to m_main.c, valgrind_main(), section "Tell the tool
478 about the initial client memory permissions". See comments there
483 /* Tell aspacem where the client's kernel commpage is */
484 #if defined(VGA_amd64)
485 /* commpage 0x7fff:ffe00000+ - not in vm_region */
486 // GrP fixme check again
487 VG_(am_notify_client_mmap
)(0x7fffffe00000, 0x7ffffffff000-0x7fffffe00000,
488 VKI_PROT_READ
|VKI_PROT_EXEC
, 0, -1, 0);
490 #elif defined(VGA_x86)
491 /* commpage 0xfffec000+ - not in vm_region */
492 // GrP fixme check again
493 VG_(am_notify_client_mmap
)(0xfffec000, 0xfffff000-0xfffec000,
494 VKI_PROT_READ
|VKI_PROT_EXEC
, 0, -1, 0);
497 # error unknown architecture
502 /*====================================================================*/
503 /*=== TOP-LEVEL: VG_(ii_create_image) ===*/
504 /*====================================================================*/
506 /* Create the client's initial memory image. */
507 IIFinaliseImageInfo
VG_(ii_create_image
)( IICreateImageInfo iicii
,
508 const VexArchInfo
* vex_archinfo
)
511 VG_(memset
)( &info
, 0, sizeof(info
) );
515 IIFinaliseImageInfo iifii
;
516 VG_(memset
)( &iifii
, 0, sizeof(iifii
) );
518 //--------------------------------------------------------------
519 // Load client executable, finding in $PATH if necessary
520 // p: get_helprequest_and_toolname() [for 'exec', 'need_help']
521 // p: layout_remaining_space [so there's space]
522 //--------------------------------------------------------------
523 VG_(debugLog
)(1, "initimg", "Loading client\n");
525 if (VG_(args_the_exename
) == NULL
)
526 VG_(err_missing_prog
)();
528 load_client(&info
, &iifii
.initial_client_IP
);
530 //--------------------------------------------------------------
531 // Set up client's environment
532 // p: set-libdir [for VG_(libdir)]
533 // p: get_helprequest_and_toolname [for toolname]
534 //--------------------------------------------------------------
535 VG_(debugLog
)(1, "initimg", "Setup client env\n");
536 env
= setup_client_env(iicii
.envp
, iicii
.toolname
);
538 //--------------------------------------------------------------
539 // Setup client stack, eip, and VG_(client_arg[cv])
540 // p: load_client() [for 'info']
541 // p: fix_environment() [for 'env']
542 //--------------------------------------------------------------
543 iicii
.clstack_end
= info
.stack_end
;
544 iifii
.clstack_max_size
= info
.stack_end
- info
.stack_start
+ 1;
546 iifii
.initial_client_SP
=
547 setup_client_stack( iicii
.argv
- 1, env
, &info
,
548 iicii
.clstack_end
, iifii
.clstack_max_size
,
553 VG_(debugLog
)(2, "initimg",
555 "initial_IP=%p initial_SP=%p stack=[%p..%p]\n",
556 (void*)(iifii
.initial_client_IP
),
557 (void*)(iifii
.initial_client_SP
),
558 (void*)(info
.stack_start
),
559 (void*)(info
.stack_end
));
562 // Tell aspacem about commpage, etc
563 record_system_memory();
565 VG_(free
)(info
.interp_name
); info
.interp_name
= NULL
;
566 VG_(free
)(info
.interp_args
); info
.interp_args
= NULL
;
571 /*====================================================================*/
572 /*=== TOP-LEVEL: VG_(ii_finalise_image) ===*/
573 /*====================================================================*/
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).
581 void VG_(ii_finalise_image
)( IIFinaliseImageInfo iifii
)
583 ThreadArchState
* arch
= &VG_(threads
)[1].arch
;
585 /* GrP fixme doesn't handle all registers from LC_THREAD or LC_UNIXTHREAD */
587 # if defined(VGP_x86_darwin)
588 vg_assert(0 == sizeof(VexGuestX86State
) % 16);
590 /* Zero out the initial state, and set up the simulated FPU in a
592 LibVEX_GuestX86_initialise(&arch
->vex
);
594 /* Zero out the shadow areas. */
595 VG_(memset
)(&arch
->vex_shadow1
, 0, sizeof(VexGuestX86State
));
596 VG_(memset
)(&arch
->vex_shadow2
, 0, sizeof(VexGuestX86State
));
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
;
602 # elif defined(VGP_amd64_darwin)
603 vg_assert(0 == sizeof(VexGuestAMD64State
) % 16);
605 /* Zero out the initial state, and set up the simulated FPU in a
607 LibVEX_GuestAMD64_initialise(&arch
->vex
);
609 /* Zero out the shadow areas. */
610 VG_(memset
)(&arch
->vex_shadow1
, 0, sizeof(VexGuestAMD64State
));
611 VG_(memset
)(&arch
->vex_shadow2
, 0, sizeof(VexGuestAMD64State
));
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
;
618 # error Unknown platform
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
));
626 #endif // defined(VGO_darwin)
628 /*--------------------------------------------------------------------*/
630 /*--------------------------------------------------------------------*/