2 /*--------------------------------------------------------------------*/
3 /*--- Startup: create initial process image on FreeBSD ---*/
4 /*--- initimg-freebsd.c ---*/
5 /*--------------------------------------------------------------------*/
8 This file is part of Valgrind, a dynamic binary instrumentation
11 Copyright (C) 2000-2009 Julian Seward
13 Copyright (C) 2018-2021 Paul Floyd
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
;
69 vg_assert( VG_(args_the_exename
) != NULL
);
70 exe_name
= VG_(find_executable
)( VG_(args_the_exename
) );
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
);
80 VG_(printf
)("valgrind: could not execute '%s'\n", exe_name
);
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
107 LD_PRELOAD=$VALGRIND_LIB/vgpreload_core-PLATFORM.so:
108 ($VALGRIND_LIB/vgpreload_TOOL-PLATFORM.so:)?
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
)
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
;
135 Int vglib_len
= VG_(strlen
)(VG_(libdir
));
140 HChar
* preload_tool_path
;
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
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",
155 /* Determine if there's a vgpreload_<tool>_<platform>.so file, and setup
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
);
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 */
177 for (cpp
= origenv
; cpp
&& *cpp
; cpp
++) {
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 */
189 for (cpp
= ret
; *origenv
; ) {
191 VG_(printf
)("XXXXXXXXX: COPY %s\n", *origenv
);
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
);
211 ld_preload_done
= True
;
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
);
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
);
242 VG_(snprintf
)(cp
, len
, "%s%s:%s",
243 ld_32_preload
, preload_string
, (*cpp
)+ld_32_preload_len
);
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
);
255 VG_(snprintf
)(cp
, len
, "%s%s", ld_32_preload
, preload_string
);
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
)) {
271 for (; i
< envc
-1; i
++) {
277 VG_(free
)(preload_string
);
280 for (i
= 0; i
< envc
; i
++) {
282 VG_(printf
)("XXXXXXXXX: FINAL %s\n", ret
[i
]);
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
)
306 VG_(printf
)("copied %p \"%s\" len %lld\n", (void*)orig
, orig
, (Long
)(cp
-orig
));
314 /* Add byte onto the string table, and return its address */
315 static HChar
*copy_bytes(HChar
**tab
, const HChar
*src
, SizeT size
)
318 /*VG_ROUNDUP(cp, sizeof(Word));*/
321 VG_(memcpy
)(cp
, src
, size
);
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
337 while (*sp
!= 0) { // skip env
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
370 lower address +-----------------+ <- client_SP (return value)
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
389 client_auxv: (output) the auxv created here
391 clstack_end: the value returned by VG_(am_startup), which is
394 clstack_max_size: the max of sysctlkern.maxssiz and VG_(clo_main_stacksize)
397 ---------------------------------------------------------------- */
398 static Addr
setup_client_stack(const void* init_sp
,
399 HChar
** new_client_envp
,
403 SizeT clstack_max_size
)
407 HChar
*strtab
; /* string table */
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 */
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 */
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) */
443 if (info
->interp_name
!= NULL
) {
445 stringsize
+= VG_(strlen
)(info
->interp_name
) + 1;
447 if (info
->interp_args
!= NULL
) {
449 stringsize
+= VG_(strlen
)(info
->interp_args
) + 1;
452 /* now scan the args we're given... */
454 stringsize
+= VG_(strlen
)( VG_(args_the_exename
) ) + 1;
457 for (i
= 0; i
< VG_(sizeXA
)( VG_(args_for_client
) ); i
++) {
459 stringsize
+= VG_(strlen
)( * (HChar
**)
460 VG_(indexXA
)( VG_(args_for_client
), i
))
464 /* ...and the environment */
466 for (cpp
= new_client_envp
; cpp
&& *cpp
; cpp
++) {
468 stringsize
+= VG_(strlen
)(*cpp
) + 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;
482 case VKI_AT_CANARYLEN
:
483 canarylen
= cauxv
->u
.a_val
;
484 /*VG_ROUNDUP(stringsize, sizeof(Word));*/
485 stringsize
+= canarylen
;
487 case VKI_AT_PAGESIZESLEN
:
488 pagesizeslen
= cauxv
->u
.a_val
;
489 /*VG_ROUNDUP(stringsize, sizeof(Word));*/
490 stringsize
+= pagesizeslen
;
493 case VKI_AT_TIMEKEEP
:
494 /*VG_ROUNDUP(stringsize, sizeof(Word));*/
495 stringsize
+= sizeof(struct vki_vdso_timehands
);
499 case VKI_AT_PS_STRINGS
:
500 stringsize
+= sizeof(struct vki_ps_strings
);
510 /* OK, now we know how big the client stack is */
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 */
519 VG_ROUNDUP(stringsize
, sizeof(Word
)); /* strings (aligned) */
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
);
539 VG_(printf
)("stringsize=%u auxsize=%u stacksize=%u maxsize=0x%lx\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 | | |
552 ower address +-----------------+ <- client_SP anon_size |
553 | round to page | | |
554 +-----------------+ <- clstack_start | |
555 | one page | | clstack_max_size
556 +-----------------+ <- anon_start v |
558 : RSVN : resvn_size |
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;
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
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
);
599 inner_HACK
= 1024*1024; // create 1M non-fault-extending stack
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
)(
612 resvn_size
-inner_HACK
,
614 anon_size
+inner_HACK
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
,
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");
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
);
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(
666 * (HChar
**) VG_(indexXA
)( VG_(args_for_client
), i
)
672 VG_(client_envp
) = (HChar
**)ptr
;
673 for (cpp
= new_client_envp
; cpp
&& *cpp
; ptr
++, cpp
++) {
674 *ptr
= (Addr
)copy_str(&strtab
, *cpp
);
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... */
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
) {
707 case VKI_AT_STACKPROT
:
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. */
716 #if defined(VGP_arm64_freebsd)
717 // FreeBSD 11+ also have HWCAP and HWCAP2
718 // but they aren't used on amd64
720 #define ARM64_SUPPORTED_HWCAP (VKI_HWCAP_ATOMICS \
727 | VKI_HWCAP_ASIMDRDM \
731 auxv
->u
.a_val
&= ARM64_SUPPORTED_HWCAP
;
733 #undef ARM64_SUPPORTED_HWCAP
741 case VKI_AT_EXECPATH
:
742 auxv
->u
.a_ptr
= copy_str(&strtab
, resolved_name
);
743 VG_(resolved_exename
) = auxv
->u
.a_ptr
;
746 if (canarylen
>= 1) {
747 auxv
->u
.a_ptr
= copy_bytes(&strtab
, orig_auxv
->u
.a_ptr
, canarylen
);
749 auxv
->a_type
= VKI_AT_IGNORE
;
752 case VKI_AT_PAGESIZES
:
753 if (pagesizeslen
>= 1) {
754 auxv
->u
.a_ptr
= copy_bytes(&strtab
, orig_auxv
->u
.a_ptr
, pagesizeslen
);
756 auxv
->a_type
= VKI_AT_IGNORE
;
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
));
769 /* @todo PJF BSDFLAGS causes serveral testcases to crash.
770 Not sure why, it seems to be used for sigfastblock */
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
;
781 auxv
->u
.a_val
= client_argv
;
784 auxv
->u
.a_val
= (Word
)VG_(client_envp
);
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 ...
792 // Again a pointer, to the VDSO base for use by rtld
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
);
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",
819 if (info
->phdr
== 0) {
820 auxv
->a_type
= VKI_AT_IGNORE
;
822 auxv
->u
.a_val
= info
->phdr
;
827 if (info
->phdr
== 0) {
828 auxv
->a_type
= VKI_AT_IGNORE
;
830 auxv
->u
.a_val
= info
->phnum
;
835 auxv
->u
.a_val
= info
->interp_offset
;
839 auxv
->u
.a_val
= info
->entry
;
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
;
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 */
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
);
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
)
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
)(
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
);
907 resvn_start
= anon_start
+ anon_size
;
908 ok
= VG_(am_create_reservation
)(
915 VG_(brk_base
) = VG_(brk_limit
) = anon_start
;
918 /* that too might have failed, but if it has, we're hosed: there
923 sres
= VG_(am_mmap_anon_fixed_client
)(
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
)
944 IIFinaliseImageInfo iifii
= {
945 .clstack_max_size
= 0,
946 .initial_client_SP
= 0,
947 .initial_client_IP
= 0,
948 .initial_client_TOC
= 0,
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;
995 SizeT szB
= (SizeT
)VG_(client_rlimit_stack
).rlim_cur
;
1002 if (VG_(clo_main_stacksize
) > 0) {
1003 szB
= VG_(clo_main_stacksize
);
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
);
1021 VG_(debugLog
)(2, "initimg",
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",
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;
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
) {
1047 if (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
;
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
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
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
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
;
1139 # error Unknown platform
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
));
1150 vg_assert(seg
->kind
== SkAnonC
);
1151 VG_TRACK(new_mem_brk
, VG_(brk_base
), seg
->end
+ 1 - VG_(brk_base
),
1153 VG_TRACK(die_mem_brk
, VG_(brk_base
), seg
->end
+ 1 - VG_(brk_base
));
1156 #endif // defined(VGO_freebsd)
1158 /*--------------------------------------------------------------------*/
1160 /*--------------------------------------------------------------------*/