s390x: Fix PC calculations with EX/EXRL
[valgrind.git] / coregrind / m_initimg / initimg-freebsd.c
bloba78875ac28a32b207cd9dc0b5ae2f4055311756d
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 #if (FREEBSD_VERS >= FREEBSD_13_0)
499 case VKI_AT_PS_STRINGS:
500 stringsize += sizeof(struct vki_ps_strings);
501 break;
502 #endif
503 #if (FREEBSD_VERS >= FREEBSD_13_1)
504 // case AT_FXRNG:
505 // case AT_KPRELOAD:
506 #endif
507 default:
508 break;
512 /* OK, now we know how big the client stack is */
513 used_stacksize =
514 sizeof(Word) + /* argc */
515 (have_exename ? sizeof(HChar **) : 0) + /* argc[0] == exename */
516 sizeof(HChar **)*argc + /* argv */
517 sizeof(HChar **) + /* terminal NULL */
518 sizeof(HChar **)*envc + /* envp */
519 sizeof(HChar **) + /* terminal NULL */
520 auxsize + /* auxv */
521 VG_ROUNDUP(stringsize, sizeof(Word)); /* strings (aligned) */
523 if (0) {
524 VG_(printf)("stacksize = %u\n", used_stacksize);
527 /* client_SP is the client's stack pointer */
528 client_SP = clstack_end - used_stacksize;
529 client_SP = VG_ROUNDDN(client_SP, 16); /* make stack 16 byte aligned */
531 /* base of the string table (aligned) */
532 stringbase = strtab = (HChar *)clstack_end
533 - VG_ROUNDUP(stringsize, sizeof(int));
535 clstack_start = VG_PGROUNDDN(client_SP);
537 /* The max stack size */
538 clstack_max_size = VG_PGROUNDUP(clstack_max_size);
540 if (0) {
541 VG_(printf)("stringsize=%u auxsize=%u stacksize=%u maxsize=0x%lx\n"
542 "clstack_start %p\n"
543 "clstack_end %p\n",
544 stringsize, auxsize, used_stacksize, clstack_max_size,
545 (void*)clstack_start, (void*)clstack_end);
548 /* ==================== allocate space ==================== */
551 higher address +-----------------+ <- clstack_end ^ ^
552 | args env auxv | | |
553 | see above | | |
554 ower address +-----------------+ <- client_SP anon_size |
555 | round to page | | |
556 +-----------------+ <- clstack_start | |
557 | one page | | clstack_max_size
558 +-----------------+ <- anon_start v |
559 : : ^ |
560 : RSVN : resvn_size |
561 : : | |
562 +-----------------+ <- resvn_start v v
567 // see comment in VG_(am_startup) about getting the maxssiz from
568 // the OS, not currently feasible with x86 on amd64
569 SizeT anon_size = clstack_end - clstack_start + 1;
570 SizeT resvn_size = clstack_max_size - anon_size;
571 Addr anon_start = clstack_start;
572 Addr resvn_start = anon_start - resvn_size;
573 SizeT inner_HACK = 0;
574 Bool ok;
576 /* So far we've only accounted for space requirements down to the
577 stack pointer. If this target's ABI requires a redzone below
578 the stack pointer, we need to allocate an extra page, to
579 handle the worst case in which the stack pointer is almost at
580 the bottom of a page, and so there is insufficient room left
581 over to put the redzone in. In this case the simple thing to
582 do is allocate an extra page, by shrinking the reservation by
583 one page and growing the anonymous area by a corresponding
584 page. */
585 vg_assert(VG_STACK_REDZONE_SZB >= 0);
586 vg_assert(VG_STACK_REDZONE_SZB < VKI_PAGE_SIZE);
587 if (VG_STACK_REDZONE_SZB > 0) {
588 vg_assert(resvn_size > VKI_PAGE_SIZE);
589 resvn_size -= VKI_PAGE_SIZE;
590 anon_start -= VKI_PAGE_SIZE;
591 anon_size += VKI_PAGE_SIZE;
594 vg_assert(VG_IS_PAGE_ALIGNED(anon_size));
595 vg_assert(VG_IS_PAGE_ALIGNED(resvn_size));
596 vg_assert(VG_IS_PAGE_ALIGNED(anon_start));
597 vg_assert(VG_IS_PAGE_ALIGNED(resvn_start));
598 vg_assert(resvn_start == clstack_end + 1 - clstack_max_size);
600 # ifdef ENABLE_INNER
601 inner_HACK = 1024*1024; // create 1M non-fault-extending stack
602 # endif
604 if (0) {
605 VG_(printf)("resvn_start %#lx resvn_size 0x%lx anon_start %#lx anon_size 0x%lx\n",
606 resvn_start, resvn_size, anon_start, anon_size);
609 /* Create a shrinkable reservation followed by an anonymous
610 segment. Together these constitute a growdown stack. */
611 res = VG_(mk_SysRes_Error)(0);
612 ok = VG_(am_create_reservation)(
613 resvn_start,
614 resvn_size -inner_HACK,
615 SmUpper,
616 anon_size +inner_HACK
618 if (ok) {
619 /* allocate a stack - mmap enough space for the stack */
620 res = VG_(am_mmap_anon_fixed_client)(
621 anon_start -inner_HACK,
622 anon_size +inner_HACK,
623 info->stack_prot
626 if ((!ok) || sr_isError(res)) {
627 /* Allocation of the stack failed. We have to stop. */
628 VG_(printf)("valgrind: "
629 "I failed to allocate space for the application's stack.\n");
630 VG_(printf)("valgrind: "
631 "This may be the result of a very large --main-stacksize=\n");
632 VG_(printf)("valgrind: setting. Cannot continue. Sorry.\n\n");
633 VG_(exit)(1);
636 vg_assert(ok);
637 vg_assert(!sr_isError(res));
639 /* Record stack extent -- needed for stack-change code. */
640 VG_(clstk_start_base) = anon_start -inner_HACK;
641 VG_(clstk_end) = VG_(clstk_start_base) + anon_size +inner_HACK -1;
645 /* ==================== create client stack ==================== */
647 ptr = (Addr*)client_SP;
649 /* --- client argc --- */
650 *ptr++ = argc + (have_exename ? 1 : 0);
652 /* --- client argv --- */
653 client_argv = (Word)ptr;
654 if (info->interp_name) {
655 *ptr++ = (Addr)copy_str(&strtab, info->interp_name);
657 if (info->interp_args) {
658 *ptr++ = (Addr)copy_str(&strtab, info->interp_args);
661 if (have_exename) {
662 *ptr++ = (Addr)copy_str(&strtab, VG_(args_the_exename));
665 for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
666 *ptr++ = (Addr)copy_str(
667 &strtab,
668 * (HChar**) VG_(indexXA)( VG_(args_for_client), i )
671 *ptr++ = 0;
673 /* --- envp --- */
674 VG_(client_envp) = (HChar **)ptr;
675 for (cpp = new_client_envp; cpp && *cpp; ptr++, cpp++) {
676 *ptr = (Addr)copy_str(&strtab, *cpp);
678 *ptr++ = 0;
680 /* --- auxv --- */
681 auxv = (struct auxv *)ptr;
682 *client_auxv = (UInt *)auxv;
683 VG_(client_auxv) = (UWord *)*client_auxv;
685 for (; orig_auxv->a_type != VKI_AT_NULL; auxv++, orig_auxv++) {
687 /* copy the entry... */
688 *auxv = *orig_auxv;
691 * ...and fix up / examine the copy
692 * in general there are thee possibilities for these items
693 * 1. copy it, a common case for scalars
694 * 2. synthesize, if the value that the host gets isn't what we want
695 * 3. ignore, usually the case for pointers to memory for the host
696 * the ignored items are just left commented out
698 switch(auxv->a_type) {
700 case VKI_AT_IGNORE:
701 case VKI_AT_PHENT:
702 case VKI_AT_PAGESZ:
703 case VKI_AT_FLAGS:
704 case VKI_AT_NOTELF:
705 case VKI_AT_UID:
706 case VKI_AT_EUID:
707 case VKI_AT_GID:
708 case VKI_AT_EGID:
709 case VKI_AT_STACKPROT:
710 case VKI_AT_NCPUS:
711 case VKI_AT_OSRELDATE:
712 case VKI_AT_PAGESIZESLEN:
713 case VKI_AT_CANARYLEN:
715 #if (FREEBSD_VERS >= FREEBSD_11)
716 case VKI_AT_EHDRFLAGS:
717 #endif
718 /* All these are pointerless, so we don't need to do
719 anything about them. */
720 break;
721 #if defined(VGP_arm64_freebsd)
722 // FreeBSD 11+ also have HWCAP and HWCAP2
723 // but they aren't used on amd64
724 case VKI_AT_HWCAP:
725 #define ARM64_SUPPORTED_HWCAP (VKI_HWCAP_ATOMICS \
726 | VKI_HWCAP_AES \
727 | VKI_HWCAP_PMULL \
728 | VKI_HWCAP_SHA1 \
729 | VKI_HWCAP_SHA2 \
730 | VKI_HWCAP_SHA512 \
731 | VKI_HWCAP_CRC32 \
732 | VKI_HWCAP_ASIMDRDM \
733 | VKI_HWCAP_FP \
734 | VKI_HWCAP_ASIMD \
735 | VKI_HWCAP_ASIMDDP)
736 auxv->u.a_val &= ARM64_SUPPORTED_HWCAP;
737 break;
738 #undef ARM64_SUPPORTED_HWCAP
739 // not yet
741 case VKI_AT_HWCAP2:
742 break;
744 #endif
746 case VKI_AT_EXECPATH:
747 auxv->u.a_ptr = copy_str(&strtab, resolved_name);
748 VG_(resolved_exename) = auxv->u.a_ptr;
749 break;
750 case VKI_AT_CANARY:
751 if (canarylen >= 1) {
752 auxv->u.a_ptr = copy_bytes(&strtab, orig_auxv->u.a_ptr, canarylen);
753 } else {
754 auxv->a_type = VKI_AT_IGNORE;
756 break;
757 case VKI_AT_PAGESIZES:
758 if (pagesizeslen >= 1) {
759 auxv->u.a_ptr = copy_bytes(&strtab, orig_auxv->u.a_ptr, pagesizeslen);
760 } else {
761 auxv->a_type = VKI_AT_IGNORE;
763 break;
764 #if 0
766 * @todo PJF this crashes intermittently
768 case VKI_AT_TIMEKEEP:
769 auxv->u.a_ptr = copy_bytes(&strtab, orig_auxv->u.a_ptr, sizeof(struct vki_vdso_timehands));
770 break;
771 #endif
773 #if (FREEBSD_VERS >= FREEBSD_13_0)
774 /* @todo PJF BSDFLAGS causes serveral testcases to crash.
775 Not sure why, it seems to be used for sigfastblock */
776 // case AT_BSDFLAGS:
777 case VKI_AT_ARGC:
778 case VKI_AT_ENVC:
779 break;
780 case VKI_AT_PS_STRINGS:
781 auxv->u.a_ptr = copy_bytes(&strtab, orig_auxv->u.a_ptr, sizeof(struct vki_ps_strings));
782 ((struct vki_ps_strings*)auxv->u.a_ptr)->ps_envstr = (char**)VG_(client_envp);
783 ((struct vki_ps_strings*)auxv->u.a_ptr)->ps_argvstr = (char**)client_argv;
784 break;
785 case VKI_AT_ARGV:
786 auxv->u.a_val = client_argv;
787 break;
788 case VKI_AT_ENVV:
789 auxv->u.a_val = (Word)VG_(client_envp);
790 break;
791 #endif
793 #if (FREEBSD_VERS >= FREEBSD_13_1)
794 // I think that this is a pointer to a "fenestrasX" structture
795 // lots of stuff that I don't understand
796 // arc4random, passing through VDSO page ...
797 // case AT_FXRNG:
798 // Again a pointer, to the VDSO base for use by rtld
799 // case AT_KPRELOAD:
800 #endif
802 #if (FREEBSD_VERS >= FREEBSD_13_2)
803 case VKI_AT_USRSTACKBASE:
804 VG_(debugLog)(2, "initimg",
805 "usrstackbase from OS %lx\n",
806 (UWord)auxv->u.a_val);
807 auxv->u.a_val = VG_(get_usrstack)();
808 VG_(debugLog)(2, "initimg",
809 "usrstackbase from aspacemgr %lx\n",
810 (UWord)auxv->u.a_val);
811 break;
812 case VKI_AT_USRSTACKLIM:
813 VG_(debugLog)(2, "initimg",
814 "usrstacklim from OS %lu (%lx)\n",
815 (UWord)auxv->u.a_val,
816 (UWord)auxv->u.a_val);
817 auxv->u.a_val = clstack_max_size;
818 VG_(debugLog)(2, "initimg",
819 "usrstacklim from aspacemgr %lu (%lx)\n",
820 clstack_max_size,
821 clstack_max_size);
823 break;
824 #endif
826 case VKI_AT_PHDR:
827 if (info->phdr == 0) {
828 auxv->a_type = VKI_AT_IGNORE;
829 } else {
830 auxv->u.a_val = info->phdr;
832 break;
834 case VKI_AT_PHNUM:
835 if (info->phdr == 0) {
836 auxv->a_type = VKI_AT_IGNORE;
837 } else {
838 auxv->u.a_val = info->phnum;
840 break;
842 case VKI_AT_BASE:
843 auxv->u.a_val = info->interp_offset;
844 break;
846 case VKI_AT_ENTRY:
847 auxv->u.a_val = info->entry;
848 break;
850 default:
851 /* stomp out anything we don't know about */
852 VG_(debugLog)(2, "initimg",
853 "stomping auxv entry %llu\n",
854 (ULong)auxv->a_type);
855 auxv->a_type = VKI_AT_IGNORE;
856 break;
859 *auxv = *orig_auxv;
860 vg_assert(auxv->a_type == VKI_AT_NULL);
862 vg_assert((strtab-stringbase) == stringsize);
864 /* client_SP is pointing at client's argc/argv */
866 if (0) {
867 VG_(printf)("startup SP = %#lx\n", client_SP);
870 if (VG_(resolved_exename) == NULL) {
871 VG_(resolved_exename) = VG_(strdup)("initimg-freebsd.sre.1", resolved_name);
874 return client_SP;
878 /* Allocate the client data segment. It is an expandable anonymous
879 mapping abutting a shrinkable reservation of size max_dseg_size.
880 The data segment starts at VG_(brk_base), which is page-aligned,
881 and runs up to VG_(brk_limit), which isn't. */
883 static void setup_client_dataseg ( SizeT max_size )
885 Bool ok;
886 SysRes sres;
887 Addr anon_start = VG_(brk_base);
888 SizeT anon_size = VKI_PAGE_SIZE;
889 Addr resvn_start = anon_start + anon_size;
890 SizeT resvn_size = max_size - anon_size;
892 vg_assert(VG_IS_PAGE_ALIGNED(anon_size));
893 vg_assert(VG_IS_PAGE_ALIGNED(resvn_size));
894 vg_assert(VG_IS_PAGE_ALIGNED(anon_start));
895 vg_assert(VG_IS_PAGE_ALIGNED(resvn_start));
897 /* Because there's been no brk activity yet: */
898 vg_assert(VG_(brk_base) == VG_(brk_limit));
900 /* Try to create the data seg and associated reservation where
901 VG_(brk_base) says. */
902 ok = VG_(am_create_reservation)(
903 resvn_start,
904 resvn_size,
905 SmLower,
906 anon_size
909 if (!ok) {
910 /* Hmm, that didn't work. Well, let aspacem suggest an address
911 it likes better, and try again with that. */
912 anon_start = VG_(am_get_advisory_client_simple)
913 ( 0/*floating*/, anon_size+resvn_size, &ok );
914 if (ok) {
915 resvn_start = anon_start + anon_size;
916 ok = VG_(am_create_reservation)(
917 resvn_start,
918 resvn_size,
919 SmLower,
920 anon_size
922 if (ok) {
923 VG_(brk_base) = VG_(brk_limit) = anon_start;
926 /* that too might have failed, but if it has, we're hosed: there
927 is no Plan C. */
929 vg_assert(ok);
931 sres = VG_(am_mmap_anon_fixed_client)(
932 anon_start,
933 anon_size,
934 VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC
936 vg_assert(!sr_isError(sres));
937 vg_assert(sr_Res(sres) == anon_start);
941 /*====================================================================*/
942 /*=== TOP-LEVEL: VG_(setup_client_initial_image) ===*/
943 /*====================================================================*/
945 /* Create the client's initial memory image. */
946 IIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo iicii,
947 const VexArchInfo* vex_archinfo )
949 ExeInfo info;
950 HChar** env = NULL;
952 IIFinaliseImageInfo iifii = {
953 .clstack_max_size = 0,
954 .initial_client_SP = 0,
955 .initial_client_IP = 0,
956 .initial_client_TOC = 0,
957 .client_auxv = NULL,
958 .arch_elf_state = VKI_INIT_ARCH_ELF_STATE,
961 //--------------------------------------------------------------
962 // Load client executable, finding in $PATH if necessary
963 // p: get_helprequest_and_toolname() [for 'exec', 'need_help']
964 // p: layout_remaining_space [so there's space]
965 //--------------------------------------------------------------
966 VG_(debugLog)(1, "initimg", "Loading client\n");
968 if (VG_(args_the_exename) == NULL) {
969 VG_(err_missing_prog)();
972 VG_(memset)(&info, 0, sizeof(info));
974 load_client(&info, &iifii.initial_client_IP, &iifii.initial_client_TOC);
976 //--------------------------------------------------------------
977 // Set up client's environment
978 // p: set-libdir [for VG_(libdir)]
979 // p: get_helprequest_and_toolname [for toolname]
980 //--------------------------------------------------------------
981 VG_(debugLog)(1, "initimg", "Setup client env\n");
982 env = setup_client_env(iicii.envp, iicii.toolname);
984 //--------------------------------------------------------------
985 // Setup client stack, eip, and VG_(client_arg[cv])
986 // p: load_client() [for 'info']
987 // p: fix_environment() [for 'env']
988 //--------------------------------------------------------------
990 /* When allocating space for the client stack, take
991 notice of the --main-stacksize value. This makes it possible
992 to run programs with very large (primary) stack requirements
993 simply by specifying --main-stacksize. */
994 /* Logic is as follows:
995 - by default, use the client's current stack rlimit
996 - if that exceeds 16M, clamp to 16M
997 - if a larger --main-stacksize value is specified, use that instead
998 - in all situations, the minimum allowed stack size is 1M
1000 void* init_sp = iicii.argv - 1;
1001 SizeT m1 = 1024 * 1024;
1002 SizeT m16 = 16 * m1;
1003 SizeT szB = (SizeT)VG_(client_rlimit_stack).rlim_cur;
1004 if (szB < m1) {
1005 szB = m1;
1007 if (szB > m16) {
1008 szB = m16;
1010 if (VG_(clo_main_stacksize) > 0) {
1011 szB = VG_(clo_main_stacksize);
1013 if (szB < m1) {
1014 szB = m1;
1016 szB = VG_PGROUNDUP(szB);
1017 VG_(debugLog)(1, "initimg",
1018 "Setup client stack: size will be %lu\n", szB);
1020 iifii.clstack_max_size = szB;
1022 iifii.initial_client_SP
1023 = setup_client_stack( init_sp, env,
1024 &info, &iifii.client_auxv,
1025 iicii.clstack_end, iifii.clstack_max_size );
1027 VG_(free)(env);
1029 VG_(debugLog)(2, "initimg",
1030 "Client info: "
1031 "initial_IP=%p initial_TOC=%p brk_base=%p\n",
1032 (void*)(iifii.initial_client_IP),
1033 (void*)(iifii.initial_client_TOC),
1034 (void*)VG_(brk_base) );
1035 VG_(debugLog)(2, "initimg",
1036 "Client info: "
1037 "initial_SP=%p max_stack_size=%lu\n",
1038 (void*)(iifii.initial_client_SP),
1039 (SizeT)iifii.clstack_max_size );
1042 //--------------------------------------------------------------
1043 // Setup client data (brk) segment. Initially a 1-page segment
1044 // which abuts a shrinkable reservation.
1045 // p: load_client() [for 'info' and hence VG_(brk_base)]
1046 //--------------------------------------------------------------
1048 SizeT m1 = 1024 * 1024;
1049 SizeT m8 = 8 * m1;
1050 SizeT dseg_max_size = (SizeT)VG_(client_rlimit_data).rlim_cur;
1051 VG_(debugLog)(1, "initimg", "Setup client data (brk) segment\n");
1052 if (dseg_max_size < m1) {
1053 dseg_max_size = m1;
1055 if (dseg_max_size > m8) {
1056 dseg_max_size = m8;
1058 dseg_max_size = VG_PGROUNDUP(dseg_max_size);
1060 setup_client_dataseg( dseg_max_size );
1063 VG_(free)(info.interp_name);
1064 info.interp_name = NULL;
1065 VG_(free)(info.interp_args);
1066 info.interp_args = NULL;
1067 return iifii;
1071 /*====================================================================*/
1072 /*=== TOP-LEVEL: VG_(finalise_thread1state) ===*/
1073 /*====================================================================*/
1075 /* Just before starting the client, we may need to make final
1076 adjustments to its initial image. Also we need to set up the VEX
1077 guest state for thread 1 (the root thread) and copy in essential
1078 starting values. This is handed the IIFinaliseImageInfo created by
1079 VG_(ii_create_image).
1081 void VG_(ii_finalise_image)( IIFinaliseImageInfo iifii )
1083 ThreadArchState* arch = &VG_(threads)[1].arch;
1085 /* We get client_{ip/sp/toc}, and start the client with
1086 all other registers zeroed. */
1088 # if defined(VGP_x86_freebsd)
1089 vg_assert(0 == sizeof(VexGuestX86State) % 16);
1091 /* Zero out the initial state, and set up the simulated FPU in a
1092 sane way. */
1093 LibVEX_GuestX86_initialise(&arch->vex);
1095 /* Zero out the shadow areas. */
1096 VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestX86State));
1097 VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestX86State));
1099 /* Put essential stuff into the new state. */
1100 arch->vex.guest_ESP = iifii.initial_client_SP;
1101 arch->vex.guest_EIP = iifii.initial_client_IP;
1103 /* initialise %cs, %ds and %ss to point at the operating systems
1104 default code, data and stack segments */
1105 asm volatile("movw %%cs, %0" : : "m" (arch->vex.guest_CS));
1106 asm volatile("movw %%ds, %0" : : "m" (arch->vex.guest_DS));
1107 asm volatile("movw %%ss, %0" : : "m" (arch->vex.guest_SS));
1109 # elif defined(VGP_amd64_freebsd)
1110 vg_assert(0 == sizeof(VexGuestAMD64State) % 16);
1112 /* Zero out the initial state, and set up the simulated FPU in a
1113 sane way. */
1114 LibVEX_GuestAMD64_initialise(&arch->vex);
1116 /* Zero out the shadow areas. */
1117 VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestAMD64State));
1118 VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestAMD64State));
1120 /* Put essential stuff into the new state. */
1121 arch->vex.guest_RSP = ((iifii.initial_client_SP - 8) & ~0xFUL) + 8;
1122 arch->vex.guest_RDI = iifii.initial_client_SP;
1123 arch->vex.guest_RIP = iifii.initial_client_IP;
1125 #elif defined(VGP_arm64_freebsd)
1127 vg_assert(0 == sizeof(VexGuestARM64State) % 16);
1129 /* Zero out the initial state, and set up the simulated FPU in a
1130 sane way. */
1131 LibVEX_GuestARM64_initialise(&arch->vex);
1133 /* Zero out the shadow areas. */
1134 VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestARM64State));
1135 VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestARM64State));
1137 /* Put essential stuff into the new state. */
1138 //arch->vex.guest_XSP = ((iifii.initial_client_SP - 8) & ~0xFUL) + 8;
1139 arch->vex.guest_XSP = iifii.initial_client_SP;
1140 arch->vex.guest_X0 = iifii.initial_client_SP;
1141 if (iifii.initial_client_SP % 16) {
1142 arch->vex.guest_X0 += 8;
1144 arch->vex.guest_PC = iifii.initial_client_IP;
1146 # else
1147 # error Unknown platform
1148 # endif
1150 /* Tell the tool that we just wrote to the registers. */
1151 VG_TRACK( post_reg_write, Vg_CoreStartup, /*tid*/1, /*offset*/0,
1152 sizeof(VexGuestArchState));
1154 /* Tell the tool about the client data segment and then kill it which will
1155 make it inaccessible/unaddressable. */
1156 const NSegment *seg = VG_(am_find_nsegment)(VG_(brk_base));
1157 vg_assert(seg);
1158 vg_assert(seg->kind == SkAnonC);
1159 VG_TRACK(new_mem_brk, VG_(brk_base), seg->end + 1 - VG_(brk_base),
1160 1/*tid*/);
1161 VG_TRACK(die_mem_brk, VG_(brk_base), seg->end + 1 - VG_(brk_base));
1164 #endif // defined(VGO_freebsd)
1166 /*--------------------------------------------------------------------*/
1167 /*--- ---*/
1168 /*--------------------------------------------------------------------*/