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-2015 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
load_client(ExeInfo * info,Addr * client_ip)61 static void load_client ( /*OUT*/ExeInfo* info,
62 /*OUT*/Addr* client_ip)
63 {
64 const 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 */
setup_client_env(HChar ** origenv,const HChar * toolname)116 static HChar** setup_client_env ( HChar** origenv, const HChar* toolname)
117 {
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));
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
146 /* Determine if there's a vgpreload_<tool>_<platform>.so file, and setup
147 preload_string. */
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);
154 } else {
155 VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so",
156 VG_(libdir), preload_core, VG_PLATFORM);
157 }
158 VG_(free)(preload_tool_path);
159
160 VG_(debugLog)(2, "initimg", "preload_string:\n");
161 VG_(debugLog)(2, "initimg", " \"%s\"\n", preload_string);
162
163 /* Count the original size of the env */
164 envc = 0;
165 for (cpp = origenv; cpp && *cpp; cpp++)
166 envc++;
167
168 /* Allocate a new space */
169 ret = VG_(malloc) ("initimg-darwin.sce.3",
170 sizeof(HChar *) * (envc+2+1)); /* 2 new entries + NULL */
171
172 /* copy it over */
173 for (cpp = ret; *origenv; )
174 *cpp++ = *origenv++;
175 *cpp = NULL;
176
177 vg_assert(envc == (cpp - ret));
178
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);
184
185 VG_(snprintf)(cp, len, "%s%s:%s",
186 ld_preload, preload_string, (*cpp)+ld_preload_len);
187
188 *cpp = cp;
189
190 ld_preload_done = True;
191 }
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);
195
196 VG_(snprintf)(cp, len, "%s%s", dyld_cache, dyld_cache_value);
197
198 *cpp = cp;
199
200 ld_preload_done = True;
201 }
202 }
203
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);
208
209 VG_(snprintf)(cp, len, "%s%s", ld_preload, preload_string);
210
211 ret[envc++] = cp;
212 }
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);
216
217 VG_(snprintf)(cp, len, "%s%s", dyld_cache, dyld_cache_value);
218
219 ret[envc++] = cp;
220 }
221
222
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))
227 break;
228
229 if (i < envc) {
230 for (; i < envc-1; i++)
231 ret[i] = ret[i+1];
232 envc--;
233 }
234
235 /* Change VYLD_ to DYLD */
236 for (i = 0; i < envc; i++) {
237 if (0 == VG_(strncmp)(ret[i], "VYLD_", 5)) {
238 ret[i][0] = 'D';
239 }
240 }
241
242
243 VG_(free)(preload_string);
244 ret[envc] = NULL;
245 return ret;
246 }
247
248
249 /*====================================================================*/
250 /*=== Setting up the client's stack ===*/
251 /*====================================================================*/
252
253 /* Add a string onto the string table, and return its address */
copy_str(HChar ** tab,const HChar * str)254 static HChar *copy_str(HChar **tab, const HChar *str)
255 {
256 HChar *cp = *tab;
257 HChar *orig = cp;
258
259 while(*str)
260 *cp++ = *str++;
261 *cp++ = '\0';
262
263 if (0)
264 VG_(printf)("copied %p \"%s\" len %lld\n", orig, orig, (Long)(cp-orig));
265
266 *tab = cp;
267
268 return orig;
269 }
270
271
272 /* ----------------------------------------------------------------
273
274 This sets up the client's initial stack, containing the args,
275 environment and aux vector.
276
277 The format of the stack on Darwin is:
278
279 higher address +-----------------+ <- clstack_end
280 | |
281 : string table :
282 | |
283 +-----------------+
284 | NULL |
285 +-----------------+
286 | executable_path | (first arg to execve())
287 +-----------------+
288 | NULL |
289 - -
290 | envp |
291 +-----------------+
292 | NULL |
293 - -
294 | argv |
295 +-----------------+
296 | argc |
297 +-----------------+
298 | mach_header * | (dynamic only)
299 lower address +-----------------+ <- sp
300 | undefined |
301 : :
302
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.
306
307 ---------------------------------------------------------------- */
308
309 static
setup_client_stack(void * init_sp,HChar ** orig_envp,const ExeInfo * info,Addr clstack_end,SizeT clstack_max_size,const VexArchInfo * vex_archinfo)310 Addr setup_client_stack( void* init_sp,
311 HChar** orig_envp,
312 const ExeInfo* info,
313 Addr clstack_end,
314 SizeT clstack_max_size,
315 const VexArchInfo* vex_archinfo )
316 {
317 HChar **cpp;
318 HChar *strtab; /* string table */
319 HChar *stringbase;
320 Addr *ptr;
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) */
327 Addr clstack_start;
328 Int i;
329
330 vg_assert(VG_IS_PAGE_ALIGNED(clstack_end+1));
331 vg_assert( VG_(args_for_client) );
332
333 /* ==================== compute sizes ==================== */
334
335 /* first of all, work out how big the client stack will be */
336 stringsize = 0;
337 auxsize = 0;
338
339 /* paste on the extra args if the loader needs them (ie, the #!
340 interpreter and its argument) */
341 argc = 0;
342 if (info->interp_name != NULL) {
343 argc++;
344 stringsize += VG_(strlen)(info->interp_name) + 1;
345 }
346 if (info->interp_args != NULL) {
347 argc++;
348 stringsize += VG_(strlen)(info->interp_args) + 1;
349 }
350
351 /* now scan the args we're given... */
352 stringsize += VG_(strlen)( VG_(args_the_exename) ) + 1;
353
354 for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
355 argc++;
356 stringsize += VG_(strlen)( * (HChar**)
357 VG_(indexXA)( VG_(args_for_client), i ))
358 + 1;
359 }
360
361 /* ...and the environment */
362 envc = 0;
363 for (cpp = orig_envp; cpp && *cpp; cpp++) {
364 envc++;
365 stringsize += VG_(strlen)(*cpp) + 1;
366 }
367
368 /* Darwin executable_path + NULL */
369 auxsize += 2 * sizeof(Word);
370 if (info->executable_path) {
371 stringsize += 1 + VG_(strlen)(info->executable_path);
372 }
373
374 /* Darwin mach_header */
375 if (info->dynamic) auxsize += sizeof(Word);
376
377 /* OK, now we know how big the client stack is */
378 stacksize =
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 */
385 auxsize + /* auxv */
386 VG_ROUNDUP(stringsize, sizeof(Word)); /* strings (aligned) */
387
388 if (0) VG_(printf)("stacksize = %d\n", stacksize);
389
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 */
393
394 /* base of the string table (aligned) */
395 stringbase = strtab = (HChar *)clstack_end
396 - VG_ROUNDUP(stringsize, sizeof(int));
397
398 /* The max stack size */
399 clstack_max_size = VG_PGROUNDUP(clstack_max_size);
400
401 /* Darwin stack is chosen by the ume loader */
402 clstack_start = clstack_end + 1 - clstack_max_size;
403
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;
408
409 if (0)
410 VG_(printf)("stringsize=%d auxsize=%d stacksize=%d maxsize=0x%x\n"
411 "clstack_start %p\n"
412 "clstack_end %p\n",
413 stringsize, auxsize, stacksize, (Int)clstack_max_size,
414 (void*)clstack_start, (void*)clstack_end);
415
416 /* ==================== allocate space ==================== */
417
418 /* Stack was allocated by the ume loader. */
419
420 /* ==================== create client stack ==================== */
421
422 ptr = (Addr*)client_SP;
423
424 /* --- mach_header --- */
425 if (info->dynamic) *ptr++ = info->text;
426
427 /* --- client argc --- */
428 *ptr++ = (Addr)(argc + 1);
429
430 /* --- client argv --- */
431 if (info->interp_name) {
432 *ptr++ = (Addr)copy_str(&strtab, info->interp_name);
433 VG_(free)(info->interp_name);
434 }
435 if (info->interp_args) {
436 *ptr++ = (Addr)copy_str(&strtab, info->interp_args);
437 VG_(free)(info->interp_args);
438 }
439
440 *ptr++ = (Addr)copy_str(&strtab, VG_(args_the_exename));
441
442 for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
443 *ptr++ = (Addr)copy_str(
444 &strtab,
445 * (HChar**) VG_(indexXA)( VG_(args_for_client), i )
446 );
447 }
448 *ptr++ = 0;
449
450 /* --- envp --- */
451 VG_(client_envp) = (HChar **)ptr;
452 for (cpp = orig_envp; cpp && *cpp; ptr++, cpp++)
453 *ptr = (Addr)copy_str(&strtab, *cpp);
454 *ptr++ = 0;
455
456 /* --- executable_path + NULL --- */
457 if (info->executable_path)
458 *ptr++ = (Addr)copy_str(&strtab, info->executable_path);
459 else
460 *ptr++ = 0;
461 *ptr++ = 0;
462
463 vg_assert((strtab-stringbase) == stringsize);
464
465 /* client_SP is pointing at client's argc/argv */
466
467 if (0) VG_(printf)("startup SP = %#lx\n", client_SP);
468 return client_SP;
469 }
470
471
472 /*====================================================================*/
473 /*=== Record system memory regions ===*/
474 /*====================================================================*/
475
record_system_memory(void)476 static void record_system_memory(void)
477 {
478 /* JRS 2014-Jul-08: this messes up the sync checker, because the
479 information that the kernel gives us doesn't include anything
480 about the commpage mapping. This functionality has therefore
481 been moved to m_main.c, valgrind_main(), section "Tell the tool
482 about the initial client memory permissions". See comments there
483 for rationale. */
484 return;
485 /*NOTREACHED*/
486
487 /* Tell aspacem where the client's kernel commpage is */
488 #if defined(VGA_amd64)
489 /* commpage 0x7fff:ffe00000+ - not in vm_region */
490 // GrP fixme check again
491 VG_(am_notify_client_mmap)(0x7fffffe00000, 0x7ffffffff000-0x7fffffe00000,
492 VKI_PROT_READ|VKI_PROT_EXEC, 0, -1, 0);
493
494 #elif defined(VGA_x86)
495 /* commpage 0xfffec000+ - not in vm_region */
496 // GrP fixme check again
497 VG_(am_notify_client_mmap)(0xfffec000, 0xfffff000-0xfffec000,
498 VKI_PROT_READ|VKI_PROT_EXEC, 0, -1, 0);
499
500 #else
501 # error unknown architecture
502 #endif
503 }
504
505
506 /*====================================================================*/
507 /*=== TOP-LEVEL: VG_(ii_create_image) ===*/
508 /*====================================================================*/
509
510 /* Create the client's initial memory image. */
VG_(ii_create_image)511 IIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo iicii,
512 const VexArchInfo* vex_archinfo )
513 {
514 ExeInfo info;
515 VG_(memset)( &info, 0, sizeof(info) );
516
517 HChar** env = NULL;
518
519 IIFinaliseImageInfo iifii;
520 VG_(memset)( &iifii, 0, sizeof(iifii) );
521
522 //--------------------------------------------------------------
523 // Load client executable, finding in $PATH if necessary
524 // p: get_helprequest_and_toolname() [for 'exec', 'need_help']
525 // p: layout_remaining_space [so there's space]
526 //--------------------------------------------------------------
527 VG_(debugLog)(1, "initimg", "Loading client\n");
528
529 if (VG_(args_the_exename) == NULL)
530 VG_(err_missing_prog)();
531
532 load_client(&info, &iifii.initial_client_IP);
533
534 //--------------------------------------------------------------
535 // Set up client's environment
536 // p: set-libdir [for VG_(libdir)]
537 // p: get_helprequest_and_toolname [for toolname]
538 //--------------------------------------------------------------
539 VG_(debugLog)(1, "initimg", "Setup client env\n");
540 env = setup_client_env(iicii.envp, iicii.toolname);
541
542 //--------------------------------------------------------------
543 // Setup client stack, eip, and VG_(client_arg[cv])
544 // p: load_client() [for 'info']
545 // p: fix_environment() [for 'env']
546 //--------------------------------------------------------------
547 iicii.clstack_end = info.stack_end;
548 iifii.clstack_max_size = info.stack_end - info.stack_start + 1;
549
550 iifii.initial_client_SP =
551 setup_client_stack( iicii.argv - 1, env, &info,
552 iicii.clstack_end, iifii.clstack_max_size,
553 vex_archinfo );
554
555 VG_(free)(env);
556
557 VG_(debugLog)(2, "initimg",
558 "Client info: "
559 "initial_IP=%p initial_SP=%p stack=[%p..%p]\n",
560 (void*)(iifii.initial_client_IP),
561 (void*)(iifii.initial_client_SP),
562 (void*)(info.stack_start),
563 (void*)(info.stack_end));
564
565
566 // Tell aspacem about commpage, etc
567 record_system_memory();
568
569 return iifii;
570 }
571
572
573 /*====================================================================*/
574 /*=== TOP-LEVEL: VG_(ii_finalise_image) ===*/
575 /*====================================================================*/
576
577 /* Just before starting the client, we may need to make final
578 adjustments to its initial image. Also we need to set up the VEX
579 guest state for thread 1 (the root thread) and copy in essential
580 starting values. This is handed the IIFinaliseImageInfo created by
581 VG_(ii_create_image).
582 */
VG_(ii_finalise_image)583 void VG_(ii_finalise_image)( IIFinaliseImageInfo iifii )
584 {
585 ThreadArchState* arch = &VG_(threads)[1].arch;
586
587 /* GrP fixme doesn't handle all registers from LC_THREAD or LC_UNIXTHREAD */
588
589 # if defined(VGP_x86_darwin)
590 vg_assert(0 == sizeof(VexGuestX86State) % 16);
591
592 /* Zero out the initial state, and set up the simulated FPU in a
593 sane way. */
594 LibVEX_GuestX86_initialise(&arch->vex);
595
596 /* Zero out the shadow areas. */
597 VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestX86State));
598 VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestX86State));
599
600 /* Put essential stuff into the new state. */
601 arch->vex.guest_ESP = iifii.initial_client_SP;
602 arch->vex.guest_EIP = iifii.initial_client_IP;
603
604 # elif defined(VGP_amd64_darwin)
605 vg_assert(0 == sizeof(VexGuestAMD64State) % 16);
606
607 /* Zero out the initial state, and set up the simulated FPU in a
608 sane way. */
609 LibVEX_GuestAMD64_initialise(&arch->vex);
610
611 /* Zero out the shadow areas. */
612 VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestAMD64State));
613 VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestAMD64State));
614
615 /* Put essential stuff into the new state. */
616 arch->vex.guest_RSP = iifii.initial_client_SP;
617 arch->vex.guest_RIP = iifii.initial_client_IP;
618
619 # else
620 # error Unknown platform
621 # endif
622
623 /* Tell the tool that we just wrote to the registers. */
624 VG_TRACK( post_reg_write, Vg_CoreStartup, /*tid*/1, /*offset*/0,
625 sizeof(VexGuestArchState));
626 }
627
628 #endif // defined(VGO_darwin)
629
630 /*--------------------------------------------------------------------*/
631 /*--- end ---*/
632 /*--------------------------------------------------------------------*/
633