regtest: forgot to add the right options for bug98317 on FreeBSD
[valgrind.git] / coregrind / m_initimg / initimg-freebsd.c
blob6749e849fc544125a5a2203616a4a0bc1626cb4c
2 /*--------------------------------------------------------------------*/
3 /*--- Startup: create initial process image on FreeBSD ---*/
4 /*--- initimg-freebsd.c ---*/
5 /*--------------------------------------------------------------------*/
7 /*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
11 Copyright (C) 2000-2009 Julian Seward
12 jseward@acm.org
13 Copyright (C) 2018-2021 Paul Floyd
14 pjfloyd@wanadoo.fr
16 This program is free software; you can redistribute it and/or
17 modify it under the terms of the GNU General Public License as
18 published by the Free Software Foundation; either version 2 of the
19 License, or (at your option) any later version.
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, see <http://www.gnu.org/licenses/>.
29 The GNU General Public License is contained in the file COPYING.
32 #if defined(VGO_freebsd)
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_syscall.h"
50 #include "pub_core_tooliface.h" /* VG_TRACK */
51 #include "pub_core_threadstate.h" /* ThreadArchState */
52 #include "pub_core_pathscan.h"
53 #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,
63 /*OUT*/Addr* client_toc)
65 const HChar* exe_name;
66 Int ret;
67 SysRes res;
69 vg_assert( VG_(args_the_exename) != NULL);
70 exe_name = VG_(find_executable)( VG_(args_the_exename) );
72 if (!exe_name) {
73 VG_(printf)("valgrind: %s: command not found\n", VG_(args_the_exename));
74 VG_(exit)(127); // 127 is Posix NOTFOUND
77 VG_(memset)(info, 0, sizeof(*info));
78 ret = VG_(do_exec)(exe_name, info);
79 if (ret < 0) {
80 VG_(printf)("valgrind: could not execute '%s'\n", exe_name);
81 VG_(exit)(1);
84 // The client was successfully loaded! Continue.
86 /* Get hold of a file descriptor which refers to the client
87 executable. This is needed for attaching to GDB. */
88 res = VG_(open)(exe_name, VKI_O_RDONLY, VKI_S_IRUSR);
89 if (!sr_isError(res)) {
90 VG_(cl_exec_fd) = sr_Res(res);
93 /* Copy necessary bits of 'info' that were filled in */
94 *client_ip = info->init_ip;
95 *client_toc = info->init_toc;
96 VG_(brk_base) = VG_(brk_limit) = VG_PGROUNDUP(info->brkbase);
100 /*====================================================================*/
101 /*=== Setting up the client's environment ===*/
102 /*====================================================================*/
104 /* Prepare the client's environment. This is basically a copy of our
105 environment, except:
107 LD_PRELOAD=$VALGRIND_LIB/vgpreload_core-PLATFORM.so:
108 ($VALGRIND_LIB/vgpreload_TOOL-PLATFORM.so:)?
109 $LD_PRELOAD
111 If this is missing, then it is added.
113 Also, remove any binding for VALGRIND_LAUNCHER=. The client should
114 not be able to see this.
116 If this needs to handle any more variables it should be hacked
117 into something table driven. The copy is VG_(malloc)'d space.
119 static HChar** setup_client_env ( HChar** origenv, const HChar* toolname)
121 vg_assert(origenv);
122 vg_assert(toolname);
124 const HChar* preload_core = "vgpreload_core";
125 const HChar* ld_preload = "LD_PRELOAD=";
126 const HChar* v_launcher = VALGRIND_LAUNCHER "=";
127 Int ld_preload_len = VG_(strlen)( ld_preload );
128 Int v_launcher_len = VG_(strlen)( v_launcher );
129 Bool ld_preload_done = False;
130 #if defined(VGP_x86_freebsd)
131 const HChar* ld_32_preload = "LD_32_PRELOAD=";
132 Int ld_32_preload_len = VG_(strlen)( ld_32_preload );
133 Bool ld_32_preload_done = False;
134 #endif
135 Int vglib_len = VG_(strlen)(VG_(libdir));
136 Bool debug = False;
138 HChar** cpp;
139 HChar** ret;
140 HChar* preload_tool_path;
141 Int envc;
142 Int i;
144 /* Alloc space for the vgpreload_core.so path and vgpreload_<tool>.so
145 paths. We might not need the space for vgpreload_<tool>.so, but it
146 doesn't hurt to over-allocate briefly. The 16s are just cautious
147 slop. */
148 Int preload_core_path_len = vglib_len + VG_(strlen)(preload_core)
149 + sizeof(VG_PLATFORM) + 16;
150 Int preload_tool_path_len = vglib_len + VG_(strlen)(toolname)
151 + sizeof(VG_PLATFORM) + 16;
152 Int preload_string_len = preload_core_path_len + preload_tool_path_len;
153 HChar* preload_string = VG_(malloc)("initimg-freebsd.sce.1",
154 preload_string_len);
155 /* Determine if there's a vgpreload_<tool>_<platform>.so file, and setup
156 preload_string. */
157 preload_tool_path = VG_(malloc)("initimg-freebsd.sce.2", preload_tool_path_len);
158 VG_(snprintf)(preload_tool_path, preload_tool_path_len,
159 "%s/vgpreload_%s-%s.so", VG_(libdir), toolname, VG_PLATFORM);
160 if (VG_(access)(preload_tool_path, True/*r*/, False/*w*/, False/*x*/) == 0) {
161 VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so:%s",
162 VG_(libdir), preload_core, VG_PLATFORM, preload_tool_path);
163 } else {
164 VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so",
165 VG_(libdir), preload_core, VG_PLATFORM);
167 VG_(free)(preload_tool_path);
169 VG_(debugLog)(2, "initimg", "preload_string:\n");
170 VG_(debugLog)(2, "initimg", " \"%s\"\n", preload_string);
172 /* Count the original size of the env */
173 if (debug) {
174 VG_(printf)("\n\n");
176 envc = 0;
177 for (cpp = origenv; cpp && *cpp; cpp++) {
178 envc++;
179 if (debug) {
180 VG_(printf)("XXXXXXXXX: BEFORE %s\n", *cpp);
184 /* Allocate a new space */
185 ret = VG_(malloc) ("initimg-freebsd.sce.3",
186 sizeof(HChar *) * (envc+2+1)); /* 2 new entries + NULL */
188 /* copy it over */
189 for (cpp = ret; *origenv; ) {
190 if (debug) {
191 VG_(printf)("XXXXXXXXX: COPY %s\n", *origenv);
193 *cpp++ = *origenv++;
195 *cpp = NULL;
196 *(cpp + 1) = NULL;
198 vg_assert(envc == (cpp - ret));
200 /* Walk over the new environment, mashing as we go */
201 for (cpp = ret; cpp && *cpp; cpp++) {
202 if (VG_(memcmp)(*cpp, ld_preload, ld_preload_len) == 0) {
203 Int len = VG_(strlen)(*cpp) + preload_string_len;
204 HChar *cp = VG_(malloc)("initimg-freebsd.sce.4", len);
206 VG_(snprintf)(cp, len, "%s%s:%s",
207 ld_preload, preload_string, (*cpp)+ld_preload_len);
209 *cpp = cp;
211 ld_preload_done = True;
213 if (debug) {
214 VG_(printf)("XXXXXXXXX: MASH %s\n", *cpp);
218 /* Add the missing bits */
219 if (!ld_preload_done) {
220 Int len = ld_preload_len + preload_string_len;
221 HChar *cp = VG_(malloc) ("initimg-freebsd.sce.5", len);
223 VG_(snprintf)(cp, len, "%s%s", ld_preload, preload_string);
225 ret[envc++] = cp;
226 if (debug) {
227 VG_(printf)("XXXXXXXXX: ADD %s\n", cp);
231 #if defined(VGP_x86_freebsd)
232 /* If we're running a 32 bit binary, ld-elf32.so.1 may be looking for
233 * a different variable name. Or it might be a 32 bit ld-elf.so.1 in a
234 * chroot. Cover both cases. */
235 if (VG_(is32on64)()) {
236 for (cpp = ret; cpp && *cpp; cpp++) {
237 if (VG_(memcmp)(*cpp, ld_32_preload, ld_32_preload_len) == 0) {
238 Int len = VG_(strlen)(*cpp) + preload_string_len;
239 HChar *cp = VG_(malloc)("initimg-freebsd.sce.4a", len);
240 vg_assert(cp);
242 VG_(snprintf)(cp, len, "%s%s:%s",
243 ld_32_preload, preload_string, (*cpp)+ld_32_preload_len);
245 *cpp = cp;
247 ld_32_preload_done = True;
250 if (!ld_32_preload_done) {
251 Int len = ld_32_preload_len + preload_string_len;
252 HChar *cp = VG_(malloc) ("initimg-freebsd.sce.5a", len);
253 vg_assert(cp);
255 VG_(snprintf)(cp, len, "%s%s", ld_32_preload, preload_string);
257 ret[envc++] = cp;
260 #endif
262 /* ret[0 .. envc-1] is live now. */
263 /* Find and remove a binding for VALGRIND_LAUNCHER. */
264 for (i = 0; i < envc; i++) {
265 if (0 == VG_(memcmp)(ret[i], v_launcher, v_launcher_len)) {
266 break;
270 if (i < envc) {
271 for (; i < envc-1; i++) {
272 ret[i] = ret[i+1];
274 envc--;
277 VG_(free)(preload_string);
278 ret[envc] = NULL;
280 for (i = 0; i < envc; i++) {
281 if (debug) {
282 VG_(printf)("XXXXXXXXX: FINAL %s\n", ret[i]);
286 return ret;
290 /*====================================================================*/
291 /*=== Setting up the client's stack ===*/
292 /*====================================================================*/
294 /* Add a string onto the string table, and return its address */
295 static HChar *copy_str(HChar **tab, const HChar *str)
297 HChar *cp = *tab;
298 HChar *orig = cp;
300 while(*str) {
301 *cp++ = *str++;
303 *cp++ = '\0';
305 if (0) {
306 VG_(printf)("copied %p \"%s\" len %lld\n", (void*)orig, orig, (Long)(cp-orig));
309 *tab = cp;
311 return orig;
314 /* Add byte onto the string table, and return its address */
315 static HChar *copy_bytes(HChar **tab, const HChar *src, SizeT size)
317 HChar *cp = *tab;
318 /*VG_ROUNDUP(cp, sizeof(Word));*/
319 HChar *orig = cp;
321 VG_(memcpy)(cp, src, size);
323 *tab = cp+size;
325 return orig;
328 static const struct auxv *find_auxv(const UWord* sp)
330 sp++; // skip argc (Nb: is word-sized, not int-sized!)
332 while (*sp != 0) { // skip argv
333 sp++;
335 sp++;
337 while (*sp != 0) { // skip env
338 sp++;
340 sp++;
342 return (const struct auxv *)sp;
345 /* ----------------------------------------------------------------
347 This sets up the client's initial stack, containing the args,
348 environment and aux vector.
350 The format of the stack is:
352 higher address +-----------------+ <- clstack_end
354 : string table :
356 +-----------------+
357 | AT_NULL |
359 | auxv |
360 +-----------------+
361 | NULL |
363 | envp |
364 +-----------------+
365 | NULL |
367 | argv |
368 +-----------------+
369 | argc |
370 lower address +-----------------+ <- client_SP (return value)
371 | undefined |
374 Allocate and create the initial client stack. It is allocated down
375 from clstack_end, which was previously determined by the address
376 space manager. The returned value is the SP value for the client.
378 The client's auxv is created by copying and modifying our own one.
380 init_sp: used to find the auxv passed by the OS to V
381 some of it will be used to generate the client auxv
383 new_client_envp: this is a copy of the original client envp
384 with LD_PRELOADs added and VALGRIND_LAUNCHER removed
386 info: structure containing about the memory mappings of the
387 exe (text and stack)
389 client_auxv: (output) the auxv created here
391 clstack_end: the value returned by VG_(am_startup), which is
392 128G
394 clstack_max_size: the max of sysctlkern.maxssiz and VG_(clo_main_stacksize)
395 aspacem_maxAddr
397 ---------------------------------------------------------------- */
398 static Addr setup_client_stack(const void* init_sp,
399 HChar** new_client_envp,
400 const ExeInfo* info,
401 UInt** client_auxv,
402 Addr clstack_end,
403 SizeT clstack_max_size )
405 SysRes res;
406 HChar **cpp;
407 HChar *strtab; /* string table */
408 HChar *stringbase;
409 Addr *ptr;
410 struct auxv *auxv;
411 const struct auxv *orig_auxv;
412 const struct auxv *cauxv;
413 unsigned stringsize; /* total size of strings in bytes */
414 unsigned auxsize; /* total size of auxv in bytes */
415 Int argc; /* total argc */
416 Int envc; /* total number of env vars */
417 unsigned used_stacksize; /* total used client stack size */
418 Addr client_SP; /* client stack base (initial SP) */
419 Addr clstack_start; /* client_SP rounded down to nearest page */
420 Int i;
421 Bool have_exename;
422 Word client_argv;
424 vg_assert(VG_IS_PAGE_ALIGNED(clstack_end+1));
425 vg_assert( VG_(args_for_client) );
427 const HChar *exe_name = VG_(find_executable)(VG_(args_the_exename));
428 HChar resolved_name[VKI_PATH_MAX];
429 VG_(realpath)(exe_name, resolved_name);
431 /* use our own auxv as a prototype */
432 orig_auxv = find_auxv(init_sp);
434 /* ==================== compute sizes ==================== */
436 /* first of all, work out how big the client stack will be */
437 stringsize = 0;
438 have_exename = VG_(args_the_exename) != NULL;
440 /* paste on the extra args if the loader needs them (ie, the #!
441 interpreter and its argument) */
442 argc = 0;
443 if (info->interp_name != NULL) {
444 argc++;
445 stringsize += VG_(strlen)(info->interp_name) + 1;
447 if (info->interp_args != NULL) {
448 argc++;
449 stringsize += VG_(strlen)(info->interp_args) + 1;
452 /* now scan the args we're given... */
453 if (have_exename) {
454 stringsize += VG_(strlen)( VG_(args_the_exename) ) + 1;
457 for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
458 argc++;
459 stringsize += VG_(strlen)( * (HChar**)
460 VG_(indexXA)( VG_(args_for_client), i ))
461 + 1;
464 /* ...and the environment */
465 envc = 0;
466 for (cpp = new_client_envp; cpp && *cpp; cpp++) {
467 envc++;
468 stringsize += VG_(strlen)(*cpp) + 1;
471 Int canarylen = -1;
472 Int pagesizeslen = -1;
474 /* now, how big is the auxv? */
475 auxsize = sizeof(*auxv); /* there's always at least one entry: AT_NULL */
476 for (cauxv = orig_auxv; cauxv->a_type != VKI_AT_NULL; cauxv++) {
477 auxsize += sizeof(*cauxv);
478 switch(cauxv->a_type) {
479 case VKI_AT_EXECPATH:
480 stringsize += VG_(strlen)(resolved_name) + 1;
481 break;
482 case VKI_AT_CANARYLEN:
483 canarylen = cauxv->u.a_val;
484 /*VG_ROUNDUP(stringsize, sizeof(Word));*/
485 stringsize += canarylen;
486 break;
487 case VKI_AT_PAGESIZESLEN:
488 pagesizeslen = cauxv->u.a_val;
489 /*VG_ROUNDUP(stringsize, sizeof(Word));*/
490 stringsize += pagesizeslen;
491 break;
492 #if 0
493 case VKI_AT_TIMEKEEP:
494 /*VG_ROUNDUP(stringsize, sizeof(Word));*/
495 stringsize += sizeof(struct vki_vdso_timehands);
496 break;
497 #endif
498 // from FreeBSD 13
499 case VKI_AT_PS_STRINGS:
500 stringsize += sizeof(struct vki_ps_strings);
501 break;
502 // from FreeBSD 13.1
503 // case AT_FXRNG:
504 // case AT_KPRELOAD:
505 default:
506 break;
510 /* OK, now we know how big the client stack is */
511 used_stacksize =
512 sizeof(Word) + /* argc */
513 (have_exename ? sizeof(HChar **) : 0) + /* argc[0] == exename */
514 sizeof(HChar **)*argc + /* argv */
515 sizeof(HChar **) + /* terminal NULL */
516 sizeof(HChar **)*envc + /* envp */
517 sizeof(HChar **) + /* terminal NULL */
518 auxsize + /* auxv */
519 VG_ROUNDUP(stringsize, sizeof(Word)); /* strings (aligned) */
521 if (0) {
522 VG_(printf)("stacksize = %u\n", used_stacksize);
525 /* client_SP is the client's stack pointer */
526 client_SP = clstack_end - used_stacksize;
527 client_SP = VG_ROUNDDN(client_SP, 16); /* make stack 16 byte aligned */
529 /* base of the string table (aligned) */
530 stringbase = strtab = (HChar *)clstack_end
531 - VG_ROUNDUP(stringsize, sizeof(int));
533 clstack_start = VG_PGROUNDDN(client_SP);
535 /* The max stack size */
536 clstack_max_size = VG_PGROUNDUP(clstack_max_size);
538 if (0) {
539 VG_(printf)("stringsize=%u auxsize=%u stacksize=%u maxsize=0x%lx\n"
540 "clstack_start %p\n"
541 "clstack_end %p\n",
542 stringsize, auxsize, used_stacksize, clstack_max_size,
543 (void*)clstack_start, (void*)clstack_end);
546 /* ==================== allocate space ==================== */
549 higher address +-----------------+ <- clstack_end ^ ^
550 | args env auxv | | |
551 | see above | | |
552 ower address +-----------------+ <- client_SP anon_size |
553 | round to page | | |
554 +-----------------+ <- clstack_start | |
555 | one page | | clstack_max_size
556 +-----------------+ <- anon_start v |
557 : : ^ |
558 : RSVN : resvn_size |
559 : : | |
560 +-----------------+ <- resvn_start v v
565 // see comment in VG_(am_startup) about getting the maxssiz from
566 // the OS, not currently feasible with x86 on amd64
567 SizeT anon_size = clstack_end - clstack_start + 1;
568 SizeT resvn_size = clstack_max_size - anon_size;
569 Addr anon_start = clstack_start;
570 Addr resvn_start = anon_start - resvn_size;
571 SizeT inner_HACK = 0;
572 Bool ok;
574 /* So far we've only accounted for space requirements down to the
575 stack pointer. If this target's ABI requires a redzone below
576 the stack pointer, we need to allocate an extra page, to
577 handle the worst case in which the stack pointer is almost at
578 the bottom of a page, and so there is insufficient room left
579 over to put the redzone in. In this case the simple thing to
580 do is allocate an extra page, by shrinking the reservation by
581 one page and growing the anonymous area by a corresponding
582 page. */
583 vg_assert(VG_STACK_REDZONE_SZB >= 0);
584 vg_assert(VG_STACK_REDZONE_SZB < VKI_PAGE_SIZE);
585 if (VG_STACK_REDZONE_SZB > 0) {
586 vg_assert(resvn_size > VKI_PAGE_SIZE);
587 resvn_size -= VKI_PAGE_SIZE;
588 anon_start -= VKI_PAGE_SIZE;
589 anon_size += VKI_PAGE_SIZE;
592 vg_assert(VG_IS_PAGE_ALIGNED(anon_size));
593 vg_assert(VG_IS_PAGE_ALIGNED(resvn_size));
594 vg_assert(VG_IS_PAGE_ALIGNED(anon_start));
595 vg_assert(VG_IS_PAGE_ALIGNED(resvn_start));
596 vg_assert(resvn_start == clstack_end + 1 - clstack_max_size);
598 # ifdef ENABLE_INNER
599 inner_HACK = 1024*1024; // create 1M non-fault-extending stack
600 # endif
602 if (0) {
603 VG_(printf)("resvn_start %#lx resvn_size 0x%lx anon_start %#lx anon_size 0x%lx\n",
604 resvn_start, resvn_size, anon_start, anon_size);
607 /* Create a shrinkable reservation followed by an anonymous
608 segment. Together these constitute a growdown stack. */
609 res = VG_(mk_SysRes_Error)(0);
610 ok = VG_(am_create_reservation)(
611 resvn_start,
612 resvn_size -inner_HACK,
613 SmUpper,
614 anon_size +inner_HACK
616 if (ok) {
617 /* allocate a stack - mmap enough space for the stack */
618 res = VG_(am_mmap_anon_fixed_client)(
619 anon_start -inner_HACK,
620 anon_size +inner_HACK,
621 info->stack_prot
624 if ((!ok) || sr_isError(res)) {
625 /* Allocation of the stack failed. We have to stop. */
626 VG_(printf)("valgrind: "
627 "I failed to allocate space for the application's stack.\n");
628 VG_(printf)("valgrind: "
629 "This may be the result of a very large --main-stacksize=\n");
630 VG_(printf)("valgrind: setting. Cannot continue. Sorry.\n\n");
631 VG_(exit)(1);
634 vg_assert(ok);
635 vg_assert(!sr_isError(res));
637 /* Record stack extent -- needed for stack-change code. */
638 VG_(clstk_start_base) = anon_start -inner_HACK;
639 VG_(clstk_end) = VG_(clstk_start_base) + anon_size +inner_HACK -1;
643 /* ==================== create client stack ==================== */
645 ptr = (Addr*)client_SP;
647 /* --- client argc --- */
648 *ptr++ = argc + (have_exename ? 1 : 0);
650 /* --- client argv --- */
651 client_argv = (Word)ptr;
652 if (info->interp_name) {
653 *ptr++ = (Addr)copy_str(&strtab, info->interp_name);
655 if (info->interp_args) {
656 *ptr++ = (Addr)copy_str(&strtab, info->interp_args);
659 if (have_exename) {
660 *ptr++ = (Addr)copy_str(&strtab, VG_(args_the_exename));
663 for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
664 *ptr++ = (Addr)copy_str(
665 &strtab,
666 * (HChar**) VG_(indexXA)( VG_(args_for_client), i )
669 *ptr++ = 0;
671 /* --- envp --- */
672 VG_(client_envp) = (HChar **)ptr;
673 for (cpp = new_client_envp; cpp && *cpp; ptr++, cpp++) {
674 *ptr = (Addr)copy_str(&strtab, *cpp);
676 *ptr++ = 0;
678 /* --- auxv --- */
679 auxv = (struct auxv *)ptr;
680 *client_auxv = (UInt *)auxv;
681 VG_(client_auxv) = (UWord *)*client_auxv;
683 for (; orig_auxv->a_type != VKI_AT_NULL; auxv++, orig_auxv++) {
685 /* copy the entry... */
686 *auxv = *orig_auxv;
689 * ...and fix up / examine the copy
690 * in general there are thee possibilities for these items
691 * 1. copy it, a common case for scalars
692 * 2. synthesize, if the value that the host gets isn't what we want
693 * 3. ignore, usually the case for pointers to memory for the host
694 * the ignored items are just left commented out
696 switch(auxv->a_type) {
698 case VKI_AT_IGNORE:
699 case VKI_AT_PHENT:
700 case VKI_AT_PAGESZ:
701 case VKI_AT_FLAGS:
702 case VKI_AT_NOTELF:
703 case VKI_AT_UID:
704 case VKI_AT_EUID:
705 case VKI_AT_GID:
706 case VKI_AT_EGID:
707 case VKI_AT_STACKPROT:
708 case VKI_AT_NCPUS:
709 case VKI_AT_OSRELDATE:
710 case VKI_AT_PAGESIZESLEN:
711 case VKI_AT_CANARYLEN:
712 case VKI_AT_EHDRFLAGS:
713 /* All these are pointerless, so we don't need to do
714 anything about them. */
715 break;
716 #if defined(VGP_arm64_freebsd)
717 // FreeBSD 11+ also have HWCAP and HWCAP2
718 // but they aren't used on amd64
719 case VKI_AT_HWCAP:
720 #define ARM64_SUPPORTED_HWCAP (VKI_HWCAP_ATOMICS \
721 | VKI_HWCAP_AES \
722 | VKI_HWCAP_PMULL \
723 | VKI_HWCAP_SHA1 \
724 | VKI_HWCAP_SHA2 \
725 | VKI_HWCAP_SHA512 \
726 | VKI_HWCAP_CRC32 \
727 | VKI_HWCAP_ASIMDRDM \
728 | VKI_HWCAP_FP \
729 | VKI_HWCAP_ASIMD \
730 | VKI_HWCAP_ASIMDDP)
731 auxv->u.a_val &= ARM64_SUPPORTED_HWCAP;
732 break;
733 #undef ARM64_SUPPORTED_HWCAP
734 // not yet
736 case VKI_AT_HWCAP2:
737 break;
739 #endif
741 case VKI_AT_EXECPATH:
742 auxv->u.a_ptr = copy_str(&strtab, resolved_name);
743 VG_(resolved_exename) = auxv->u.a_ptr;
744 break;
745 case VKI_AT_CANARY:
746 if (canarylen >= 1) {
747 auxv->u.a_ptr = copy_bytes(&strtab, orig_auxv->u.a_ptr, canarylen);
748 } else {
749 auxv->a_type = VKI_AT_IGNORE;
751 break;
752 case VKI_AT_PAGESIZES:
753 if (pagesizeslen >= 1) {
754 auxv->u.a_ptr = copy_bytes(&strtab, orig_auxv->u.a_ptr, pagesizeslen);
755 } else {
756 auxv->a_type = VKI_AT_IGNORE;
758 break;
759 #if 0
761 * @todo PJF this crashes intermittently
763 case VKI_AT_TIMEKEEP:
764 auxv->u.a_ptr = copy_bytes(&strtab, orig_auxv->u.a_ptr, sizeof(struct vki_vdso_timehands));
765 break;
766 #endif
768 // From FreeBSD 13.0
769 /* @todo PJF BSDFLAGS causes serveral testcases to crash.
770 Not sure why, it seems to be used for sigfastblock */
771 // case AT_BSDFLAGS:
772 case VKI_AT_ARGC:
773 case VKI_AT_ENVC:
774 break;
775 case VKI_AT_PS_STRINGS:
776 auxv->u.a_ptr = copy_bytes(&strtab, orig_auxv->u.a_ptr, sizeof(struct vki_ps_strings));
777 ((struct vki_ps_strings*)auxv->u.a_ptr)->ps_envstr = (char**)VG_(client_envp);
778 ((struct vki_ps_strings*)auxv->u.a_ptr)->ps_argvstr = (char**)client_argv;
779 break;
780 case VKI_AT_ARGV:
781 auxv->u.a_val = client_argv;
782 break;
783 case VKI_AT_ENVV:
784 auxv->u.a_val = (Word)VG_(client_envp);
785 break;
787 // from FreeBSD 13.1
788 // I think that this is a pointer to a "fenestrasX" structture
789 // lots of stuff that I don't understand
790 // arc4random, passing through VDSO page ...
791 // case AT_FXRNG:
792 // Again a pointer, to the VDSO base for use by rtld
793 // case AT_KPRELOAD:
795 // from FreeBSD 13.2
796 case VKI_AT_USRSTACKBASE:
797 VG_(debugLog)(2, "initimg",
798 "usrstackbase from OS %lx\n",
799 (UWord)auxv->u.a_val);
800 auxv->u.a_val = VG_(get_usrstack)();
801 VG_(debugLog)(2, "initimg",
802 "usrstackbase from aspacemgr %lx\n",
803 (UWord)auxv->u.a_val);
804 break;
805 case VKI_AT_USRSTACKLIM:
806 VG_(debugLog)(2, "initimg",
807 "usrstacklim from OS %lu (%lx)\n",
808 (UWord)auxv->u.a_val,
809 (UWord)auxv->u.a_val);
810 auxv->u.a_val = clstack_max_size;
811 VG_(debugLog)(2, "initimg",
812 "usrstacklim from aspacemgr %lu (%lx)\n",
813 clstack_max_size,
814 clstack_max_size);
816 break;
818 case VKI_AT_PHDR:
819 if (info->phdr == 0) {
820 auxv->a_type = VKI_AT_IGNORE;
821 } else {
822 auxv->u.a_val = info->phdr;
824 break;
826 case VKI_AT_PHNUM:
827 if (info->phdr == 0) {
828 auxv->a_type = VKI_AT_IGNORE;
829 } else {
830 auxv->u.a_val = info->phnum;
832 break;
834 case VKI_AT_BASE:
835 auxv->u.a_val = info->interp_offset;
836 break;
838 case VKI_AT_ENTRY:
839 auxv->u.a_val = info->entry;
840 break;
842 default:
843 /* stomp out anything we don't know about */
844 VG_(debugLog)(2, "initimg",
845 "stomping auxv entry %llu\n",
846 (ULong)auxv->a_type);
847 auxv->a_type = VKI_AT_IGNORE;
848 break;
851 *auxv = *orig_auxv;
852 vg_assert(auxv->a_type == VKI_AT_NULL);
854 vg_assert((strtab-stringbase) == stringsize);
856 /* client_SP is pointing at client's argc/argv */
858 if (0) {
859 VG_(printf)("startup SP = %#lx\n", client_SP);
862 if (VG_(resolved_exename) == NULL) {
863 VG_(resolved_exename) = VG_(strdup)("initimg-freebsd.sre.1", resolved_name);
866 return client_SP;
870 /* Allocate the client data segment. It is an expandable anonymous
871 mapping abutting a shrinkable reservation of size max_dseg_size.
872 The data segment starts at VG_(brk_base), which is page-aligned,
873 and runs up to VG_(brk_limit), which isn't. */
875 static void setup_client_dataseg ( SizeT max_size )
877 Bool ok;
878 SysRes sres;
879 Addr anon_start = VG_(brk_base);
880 SizeT anon_size = VKI_PAGE_SIZE;
881 Addr resvn_start = anon_start + anon_size;
882 SizeT resvn_size = max_size - anon_size;
884 vg_assert(VG_IS_PAGE_ALIGNED(anon_size));
885 vg_assert(VG_IS_PAGE_ALIGNED(resvn_size));
886 vg_assert(VG_IS_PAGE_ALIGNED(anon_start));
887 vg_assert(VG_IS_PAGE_ALIGNED(resvn_start));
889 /* Because there's been no brk activity yet: */
890 vg_assert(VG_(brk_base) == VG_(brk_limit));
892 /* Try to create the data seg and associated reservation where
893 VG_(brk_base) says. */
894 ok = VG_(am_create_reservation)(
895 resvn_start,
896 resvn_size,
897 SmLower,
898 anon_size
901 if (!ok) {
902 /* Hmm, that didn't work. Well, let aspacem suggest an address
903 it likes better, and try again with that. */
904 anon_start = VG_(am_get_advisory_client_simple)
905 ( 0/*floating*/, anon_size+resvn_size, &ok );
906 if (ok) {
907 resvn_start = anon_start + anon_size;
908 ok = VG_(am_create_reservation)(
909 resvn_start,
910 resvn_size,
911 SmLower,
912 anon_size
914 if (ok) {
915 VG_(brk_base) = VG_(brk_limit) = anon_start;
918 /* that too might have failed, but if it has, we're hosed: there
919 is no Plan C. */
921 vg_assert(ok);
923 sres = VG_(am_mmap_anon_fixed_client)(
924 anon_start,
925 anon_size,
926 VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC
928 vg_assert(!sr_isError(sres));
929 vg_assert(sr_Res(sres) == anon_start);
933 /*====================================================================*/
934 /*=== TOP-LEVEL: VG_(setup_client_initial_image) ===*/
935 /*====================================================================*/
937 /* Create the client's initial memory image. */
938 IIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo iicii,
939 const VexArchInfo* vex_archinfo )
941 ExeInfo info;
942 HChar** env = NULL;
944 IIFinaliseImageInfo iifii = {
945 .clstack_max_size = 0,
946 .initial_client_SP = 0,
947 .initial_client_IP = 0,
948 .initial_client_TOC = 0,
949 .client_auxv = NULL,
950 .arch_elf_state = VKI_INIT_ARCH_ELF_STATE,
953 //--------------------------------------------------------------
954 // Load client executable, finding in $PATH if necessary
955 // p: get_helprequest_and_toolname() [for 'exec', 'need_help']
956 // p: layout_remaining_space [so there's space]
957 //--------------------------------------------------------------
958 VG_(debugLog)(1, "initimg", "Loading client\n");
960 if (VG_(args_the_exename) == NULL) {
961 VG_(err_missing_prog)();
964 VG_(memset)(&info, 0, sizeof(info));
966 load_client(&info, &iifii.initial_client_IP, &iifii.initial_client_TOC);
968 //--------------------------------------------------------------
969 // Set up client's environment
970 // p: set-libdir [for VG_(libdir)]
971 // p: get_helprequest_and_toolname [for toolname]
972 //--------------------------------------------------------------
973 VG_(debugLog)(1, "initimg", "Setup client env\n");
974 env = setup_client_env(iicii.envp, iicii.toolname);
976 //--------------------------------------------------------------
977 // Setup client stack, eip, and VG_(client_arg[cv])
978 // p: load_client() [for 'info']
979 // p: fix_environment() [for 'env']
980 //--------------------------------------------------------------
982 /* When allocating space for the client stack, take
983 notice of the --main-stacksize value. This makes it possible
984 to run programs with very large (primary) stack requirements
985 simply by specifying --main-stacksize. */
986 /* Logic is as follows:
987 - by default, use the client's current stack rlimit
988 - if that exceeds 16M, clamp to 16M
989 - if a larger --main-stacksize value is specified, use that instead
990 - in all situations, the minimum allowed stack size is 1M
992 void* init_sp = iicii.argv - 1;
993 SizeT m1 = 1024 * 1024;
994 SizeT m16 = 16 * m1;
995 SizeT szB = (SizeT)VG_(client_rlimit_stack).rlim_cur;
996 if (szB < m1) {
997 szB = m1;
999 if (szB > m16) {
1000 szB = m16;
1002 if (VG_(clo_main_stacksize) > 0) {
1003 szB = VG_(clo_main_stacksize);
1005 if (szB < m1) {
1006 szB = m1;
1008 szB = VG_PGROUNDUP(szB);
1009 VG_(debugLog)(1, "initimg",
1010 "Setup client stack: size will be %lu\n", szB);
1012 iifii.clstack_max_size = szB;
1014 iifii.initial_client_SP
1015 = setup_client_stack( init_sp, env,
1016 &info, &iifii.client_auxv,
1017 iicii.clstack_end, iifii.clstack_max_size );
1019 VG_(free)(env);
1021 VG_(debugLog)(2, "initimg",
1022 "Client info: "
1023 "initial_IP=%p initial_TOC=%p brk_base=%p\n",
1024 (void*)(iifii.initial_client_IP),
1025 (void*)(iifii.initial_client_TOC),
1026 (void*)VG_(brk_base) );
1027 VG_(debugLog)(2, "initimg",
1028 "Client info: "
1029 "initial_SP=%p max_stack_size=%lu\n",
1030 (void*)(iifii.initial_client_SP),
1031 (SizeT)iifii.clstack_max_size );
1034 //--------------------------------------------------------------
1035 // Setup client data (brk) segment. Initially a 1-page segment
1036 // which abuts a shrinkable reservation.
1037 // p: load_client() [for 'info' and hence VG_(brk_base)]
1038 //--------------------------------------------------------------
1040 SizeT m1 = 1024 * 1024;
1041 SizeT m8 = 8 * m1;
1042 SizeT dseg_max_size = (SizeT)VG_(client_rlimit_data).rlim_cur;
1043 VG_(debugLog)(1, "initimg", "Setup client data (brk) segment\n");
1044 if (dseg_max_size < m1) {
1045 dseg_max_size = m1;
1047 if (dseg_max_size > m8) {
1048 dseg_max_size = m8;
1050 dseg_max_size = VG_PGROUNDUP(dseg_max_size);
1052 setup_client_dataseg( dseg_max_size );
1055 VG_(free)(info.interp_name);
1056 info.interp_name = NULL;
1057 VG_(free)(info.interp_args);
1058 info.interp_args = NULL;
1059 return iifii;
1063 /*====================================================================*/
1064 /*=== TOP-LEVEL: VG_(finalise_thread1state) ===*/
1065 /*====================================================================*/
1067 /* Just before starting the client, we may need to make final
1068 adjustments to its initial image. Also we need to set up the VEX
1069 guest state for thread 1 (the root thread) and copy in essential
1070 starting values. This is handed the IIFinaliseImageInfo created by
1071 VG_(ii_create_image).
1073 void VG_(ii_finalise_image)( IIFinaliseImageInfo iifii )
1075 ThreadArchState* arch = &VG_(threads)[1].arch;
1077 /* We get client_{ip/sp/toc}, and start the client with
1078 all other registers zeroed. */
1080 # if defined(VGP_x86_freebsd)
1081 vg_assert(0 == sizeof(VexGuestX86State) % 16);
1083 /* Zero out the initial state, and set up the simulated FPU in a
1084 sane way. */
1085 LibVEX_GuestX86_initialise(&arch->vex);
1087 /* Zero out the shadow areas. */
1088 VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestX86State));
1089 VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestX86State));
1091 /* Put essential stuff into the new state. */
1092 arch->vex.guest_ESP = iifii.initial_client_SP;
1093 arch->vex.guest_EIP = iifii.initial_client_IP;
1095 /* initialise %cs, %ds and %ss to point at the operating systems
1096 default code, data and stack segments */
1097 asm volatile("movw %%cs, %0" : : "m" (arch->vex.guest_CS));
1098 asm volatile("movw %%ds, %0" : : "m" (arch->vex.guest_DS));
1099 asm volatile("movw %%ss, %0" : : "m" (arch->vex.guest_SS));
1101 # elif defined(VGP_amd64_freebsd)
1102 vg_assert(0 == sizeof(VexGuestAMD64State) % 16);
1104 /* Zero out the initial state, and set up the simulated FPU in a
1105 sane way. */
1106 LibVEX_GuestAMD64_initialise(&arch->vex);
1108 /* Zero out the shadow areas. */
1109 VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestAMD64State));
1110 VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestAMD64State));
1112 /* Put essential stuff into the new state. */
1113 arch->vex.guest_RSP = ((iifii.initial_client_SP - 8) & ~0xFUL) + 8;
1114 arch->vex.guest_RDI = iifii.initial_client_SP;
1115 arch->vex.guest_RIP = iifii.initial_client_IP;
1117 #elif defined(VGP_arm64_freebsd)
1119 vg_assert(0 == sizeof(VexGuestARM64State) % 16);
1121 /* Zero out the initial state, and set up the simulated FPU in a
1122 sane way. */
1123 LibVEX_GuestARM64_initialise(&arch->vex);
1125 /* Zero out the shadow areas. */
1126 VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestARM64State));
1127 VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestARM64State));
1129 /* Put essential stuff into the new state. */
1130 //arch->vex.guest_XSP = ((iifii.initial_client_SP - 8) & ~0xFUL) + 8;
1131 arch->vex.guest_XSP = iifii.initial_client_SP;
1132 arch->vex.guest_X0 = iifii.initial_client_SP;
1133 if (iifii.initial_client_SP % 16) {
1134 arch->vex.guest_X0 += 8;
1136 arch->vex.guest_PC = iifii.initial_client_IP;
1138 # else
1139 # error Unknown platform
1140 # endif
1142 /* Tell the tool that we just wrote to the registers. */
1143 VG_TRACK( post_reg_write, Vg_CoreStartup, /*tid*/1, /*offset*/0,
1144 sizeof(VexGuestArchState));
1146 /* Tell the tool about the client data segment and then kill it which will
1147 make it inaccessible/unaddressable. */
1148 const NSegment *seg = VG_(am_find_nsegment)(VG_(brk_base));
1149 vg_assert(seg);
1150 vg_assert(seg->kind == SkAnonC);
1151 VG_TRACK(new_mem_brk, VG_(brk_base), seg->end + 1 - VG_(brk_base),
1152 1/*tid*/);
1153 VG_TRACK(die_mem_brk, VG_(brk_base), seg->end + 1 - VG_(brk_base));
1156 #endif // defined(VGO_freebsd)
1158 /*--------------------------------------------------------------------*/
1159 /*--- ---*/
1160 /*--------------------------------------------------------------------*/