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 (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_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 /*--------------------------------------------------------------------*/ 630