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-2017 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 if (info->interp_args)
434 *ptr++ = (Addr)copy_str(&strtab, info->interp_args);
435
436 *ptr++ = (Addr)copy_str(&strtab, VG_(args_the_exename));
437
438 for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
439 *ptr++ = (Addr)copy_str(
440 &strtab,
441 * (HChar**) VG_(indexXA)( VG_(args_for_client), i )
442 );
443 }
444 *ptr++ = 0;
445
446 /* --- envp --- */
447 VG_(client_envp) = (HChar **)ptr;
448 for (cpp = orig_envp; cpp && *cpp; ptr++, cpp++)
449 *ptr = (Addr)copy_str(&strtab, *cpp);
450 *ptr++ = 0;
451
452 /* --- executable_path + NULL --- */
453 if (info->executable_path)
454 *ptr++ = (Addr)copy_str(&strtab, info->executable_path);
455 else
456 *ptr++ = 0;
457 *ptr++ = 0;
458
459 vg_assert((strtab-stringbase) == stringsize);
460
461 /* client_SP is pointing at client's argc/argv */
462
463 if (0) VG_(printf)("startup SP = %#lx\n", client_SP);
464 return client_SP;
465 }
466
467
468 /*====================================================================*/
469 /*=== Record system memory regions ===*/
470 /*====================================================================*/
471
record_system_memory(void)472 static void record_system_memory(void)
473 {
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
479 for rationale. */
480 return;
481 /*NOTREACHED*/
482
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);
489
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);
495
496 #else
497 # error unknown architecture
498 #endif
499 }
500
501
502 /*====================================================================*/
503 /*=== TOP-LEVEL: VG_(ii_create_image) ===*/
504 /*====================================================================*/
505
506 /* Create the client's initial memory image. */
VG_(ii_create_image)507 IIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo iicii,
508 const VexArchInfo* vex_archinfo )
509 {
510 ExeInfo info;
511 VG_(memset)( &info, 0, sizeof(info) );
512
513 HChar** env = NULL;
514
515 IIFinaliseImageInfo iifii;
516 VG_(memset)( &iifii, 0, sizeof(iifii) );
517
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");
524
525 if (VG_(args_the_exename) == NULL)
526 VG_(err_missing_prog)();
527
528 load_client(&info, &iifii.initial_client_IP);
529
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);
537
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;
545
546 iifii.initial_client_SP =
547 setup_client_stack( iicii.argv - 1, env, &info,
548 iicii.clstack_end, iifii.clstack_max_size,
549 vex_archinfo );
550
551 VG_(free)(env);
552
553 VG_(debugLog)(2, "initimg",
554 "Client info: "
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));
560
561
562 // Tell aspacem about commpage, etc
563 record_system_memory();
564
565 VG_(free)(info.interp_name); info.interp_name = NULL;
566 VG_(free)(info.interp_args); info.interp_args = NULL;
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 */
VG_(ii_finalise_image)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