in the auxiliary vector.
This is possible as Solaris 12 kernel now creates auxv even
for statically linked binaries.
n-i-bz
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15682
possible for Valgrind to arrange mapping of a kernel shared page at the
address specified in the mapfile for the guest application. There is currently
no such mechanism in Solaris. Hacky workarounds are possible, though.
-- Guest programs do not contain entries for AT_SUN_SYSSTAT_ADDR and
- AT_SUN_SYSSTAT_ZONE_ADDR in their auxilliary vectors. There is no direct way
- how to obtain addresses of these pages shared with the kernel as they are
- passed in auxv and kernel does not create auxv for statically linked binaries
- (such as Valgrind analysis tools).
- Indirect methods, such as scanning 1-page mappings found at Valgrind
- startup surrounded by reservations, could be possible. But it is hard to tell
- which page is which because their contents are filled only when a system
- cyclic is started. See get_hrusec() for reference.
- When a thread has no stack then all system calls will result in Valgrind
crash, even though such system calls use just parameters passed in registers.
This should happen only in pathological situations when a thread is created
to see this in effect. Would require awareness of syscall parameter semantics.
- Correctly print arguments of DW_CFA_ORCL_arg_loc in show_CF_instruction() when
it is implemented in libdwarf.
+- Provide tests for AT_SUN_SYSSTAT_ADDR and AT_SUN_SYSSTAT_ZONE_ADDR.
Contacts
The GNU General Public License is contained in the file COPYING.
*/
+/* Copyright 2013-2015, Ivo Raisr <ivosh@ivosh.net>. */
+
#if defined(VGO_solaris)
/* Note: This file is based on initimg-linux.c. */
return orig;
}
+/* The auxiliary vector might not be present. So we cross-check pointers from
+ argv and envp pointing to the string table. */
+static vki_auxv_t *find_original_auxv(Addr init_sp)
+{
+ HChar **sp = (HChar **) init_sp;
+ HChar *lowest_str_ptr = (HChar *) UINTPTR_MAX; // lowest ptr to string table
+
+ sp++; // skip argc
+
+ while (*sp != NULL) { // skip argv
+ if (*sp < lowest_str_ptr)
+ lowest_str_ptr = *sp;
+ sp++;
+ }
+ sp++;
+
+ while (*sp != 0) { // skip env
+ if (*sp < lowest_str_ptr)
+ lowest_str_ptr = *sp;
+ sp++;
+ }
+ sp++;
+
+ if ((Addr) sp < (Addr) lowest_str_ptr) {
+ return (vki_auxv_t *) sp;
+ } else {
+ return NULL;
+ }
+}
+
+static void copy_auxv_entry(const vki_auxv_t *orig_auxv, Int type,
+ const HChar *type_name, vki_auxv_t *auxv)
+{
+ vg_assert(auxv != NULL);
+
+ if (orig_auxv == NULL) {
+ VG_(printf)("valgrind: Cannot locate auxiliary vector.\n");
+ VG_(printf)("valgrind: Cannot continue. Sorry.\n\n");
+ VG_(exit)(1);
+ }
+
+ for ( ; orig_auxv->a_type != VKI_AT_NULL; orig_auxv++) {
+ if (orig_auxv->a_type == type) {
+ auxv->a_type = type;
+ auxv->a_un.a_val = orig_auxv->a_un.a_val;
+ return;
+ }
+ }
+
+ VG_(printf)("valgrind: Cannot locate %s in the aux\n", type_name);
+ VG_(printf)("valgrind: vector. Cannot continue. Sorry.\n\n");
+ VG_(exit)(1);
+}
/* This sets up the client's initial stack, containing the args,
environment and aux vector.
clstack_end, which was previously determined by the address space manager.
The returned value is the SP value for the client.
- Note that no aux vector is created by kernel on Solaris if the program is
- statically linked (which is our case). That means we have to build auxv
- from scratch. */
+ Note that auxiliary vector is *not* created by kernel on illumos and
+ Solaris 11 if the program is statically linked (which is our case).
+ Although we now taught Solaris 12 to create the auxiliary vector, we still
+ have to build auxv from scratch, to make the code consistent. */
-static Addr setup_client_stack(void *init_sp,
+static Addr setup_client_stack(Addr init_sp,
HChar **orig_envp,
const ExeInfo *info,
Addr clstack_end,
vg_assert(VG_(args_the_exename));
vg_assert(VG_(args_for_client));
+ /* Get the original auxv (if any). */
+ vki_auxv_t *orig_auxv = find_original_auxv(init_sp);
+
/* ==================== compute sizes ==================== */
/* First of all, work out how big the client stack will be. */
AT_PAGESZ
AT_SUN_AUXFLAFGS
AT_SUN_HWCAP
+ AT_SUN_SYSSTAT_ADDR (if supported)
+ AT_SUN_SYSSTAT_ZONE_ADDR (if supported)
AT_NULL
It would be possible to also add AT_PHENT, AT_PHNUM, AT_ENTRY,
AT_SUN_LDDATA, but they don't seem to be so important. */
auxsize = 9 * sizeof(*auxv);
+# if defined(SOLARIS_RESERVE_SYSSTAT_ADDR)
+ auxsize += sizeof(*auxv);
+# endif
+# if defined(SOLARIS_RESERVE_SYSSTAT_ZONE_ADDR)
+ auxsize += sizeof(*auxv);
+# endif
+
# if defined(VGA_x86) || defined(VGA_amd64)
/* AT_SUN_PLATFORM string. */
stringsize += VG_(strlen)("i86pc") + 1;
*/
}
+# if defined(SOLARIS_RESERVE_SYSSTAT_ADDR)
+ /* AT_SUN_SYSSTAT_ADDR */
+ copy_auxv_entry(orig_auxv, VKI_AT_SUN_SYSSTAT_ADDR,
+ "AT_SUN_SYSSTAT_ADDR", auxv);
+ VG_(change_mapping_ownership)(auxv->a_un.a_val, True);
+ auxv++;
+# endif
+
+# if defined(SOLARIS_RESERVE_SYSSTAT_ZONE_ADDR)
+ /* AT_SUN_SYSSTAT_ZONE_ADDR */
+ copy_auxv_entry(orig_auxv, VKI_AT_SUN_SYSSTAT_ZONE_ADDR,
+ "AT_SUN_SYSSTAT_ZONE_ADDR", auxv);
+ VG_(change_mapping_ownership)(auxv->a_un.a_val, True);
+ auxv++;
+# endif
+
/* AT_NULL */
auxv->a_type = VKI_AT_NULL;
auxv->a_un.a_val = 0;
- If a larger --main-stacksize value is specified, use that instead.
- In all situations, the minimum allowed stack size is 1M.
*/
- void *init_sp = iicii.argv - 1;
+ Addr init_sp = (Addr) (iicii.argv - 1);
SizeT m1 = 1024 * 1024;
SizeT m16 = 16 * m1;
SizeT szB = (SizeT)VG_(client_rlimit_stack).rlim_cur;
The GNU General Public License is contained in the file COPYING.
*/
-/* Copyright 2015-2015, Tomas Jedlicka <jedlickat@gmail.com>. */
-
/* Copyright 2013-2015, Ivo Raisr <ivosh@ivosh.net>. */
+/* Copyright 2015-2015, Tomas Jedlicka <jedlickat@gmail.com>. */
+
/* Copyright 2013, OmniTI Computer Consulting, Inc. All rights reserved. */
#if defined(VGO_solaris)
VG_(atfork)(NULL, NULL, clean_schedctl_data);
}
+/* Changes ownership of a memory mapping shared between kernel and the client
+ process. This mapping should have already been pre-arranged during process
+ address space initialization happening in kernel. Valgrind on startup created
+ a segment for this mapping categorized as Valgrind's owned anonymous.
+ Size of this mapping typically varies among Solaris versions but should be
+ page aligned.
+ If 'once_only' is 'True', it is expected this function is called once only
+ and the mapping ownership has not been changed, yet [useful during
+ initialization]. If 'False', this function can be called many times but does
+ change ownership only upon the first invocation [useful in syscall wrappers].
+ */
+void VG_(change_mapping_ownership)(Addr addr, Bool once_only)
+{
+ const NSegment *seg = VG_(am_find_anon_segment)(addr);
+ vg_assert(seg != NULL);
+ vg_assert(seg->start == addr);
+ vg_assert(VG_IS_PAGE_ALIGNED(seg->start));
+ vg_assert(VG_IS_PAGE_ALIGNED(seg->end + 1));
+ SizeT size = seg->end - seg->start + 1;
+ vg_assert(size > 0);
+
+ Bool do_change = False;
+ if (once_only) {
+ vg_assert(VG_(am_is_valid_for_valgrind)(addr, size, VKI_PROT_READ));
+ do_change = True;
+ } else {
+ if (!VG_(am_is_valid_for_client)(addr, size, VKI_PROT_READ))
+ do_change = True;
+ }
+
+ if (do_change) {
+ Bool change_ownership_OK = VG_(am_change_ownership_v_to_c)(addr, size);
+ vg_assert(change_ownership_OK);
+
+ /* Tell the tool about just discovered mapping. */
+ VG_TRACK(new_mem_startup,
+ addr, size,
+ True /* readable? */,
+ False /* writable? */,
+ False /* executable? */,
+ 0 /* di_handle */);
+ }
+}
+
/* Calculate the Fletcher-32 checksum of a given buffer. */
UInt ML_(fletcher32)(UShort *buf, SizeT blocks)
{
if (RES == 0)
return;
- /* Returned address points to a memory mapping shared between kernel
- and the process. This was already pre-arranged during process address
- space initialization happening in kernel. Valgrind on startup created
- a segment for this mapping categorized as Valgrind's owned anonymous.
- Size of this mapping varies among Solaris versions but should be
- page aligned. */
- const NSegment *seg = VG_(am_find_anon_segment)(RES);
- vg_assert(seg != NULL);
- vg_assert(seg->start == RES);
- vg_assert(VG_IS_PAGE_ALIGNED(seg->start));
- vg_assert(VG_IS_PAGE_ALIGNED(seg->end + 1));
- SizeT size = seg->end - seg->start + 1;
- vg_assert(size > 0);
-
- if (!VG_(am_is_valid_for_client)(RES, size, VKI_PROT_READ)) {
- Bool change_ownership_v_c_OK
- = VG_(am_change_ownership_v_to_c)(RES, size);
- vg_assert(change_ownership_v_c_OK);
-
- /* Tell the tool about just discovered mapping. */
- VG_TRACK(new_mem_startup,
- RES, size,
- True /* readable? */,
- False /* writable? */,
- False /* executable? */,
- 0 /* di_handle */);
- }
+ VG_(change_mapping_ownership)(RES, False);
}
#endif /* SOLARIS_GETHRT_FASTTRAP */
if (RES == 0)
return;
- /* Returned address points to a memory mapping shared between kernel
- and the process. This was already pre-arranged during process address
- space initialization happening in kernel. Valgrind on startup created
- a segment for this mapping categorized as Valgrind's owned anonymous.
- Size of this mapping varies among Solaris versions but should be
- page aligned. */
- const NSegment *seg = VG_(am_find_anon_segment)(RES);
- vg_assert(seg != NULL);
- vg_assert(seg->start == RES);
- vg_assert(VG_IS_PAGE_ALIGNED(seg->start));
- vg_assert(VG_IS_PAGE_ALIGNED(seg->end + 1));
- SizeT size = seg->end - seg->start + 1;
- vg_assert(size > 0);
-
- if (!VG_(am_is_valid_for_client)(RES, size, VKI_PROT_READ)) {
- Bool change_ownership_v_c_OK
- = VG_(am_change_ownership_v_to_c)(RES, size);
- vg_assert(change_ownership_v_c_OK);
-
- /* Tell the tool about just discovered mapping. */
- VG_TRACK(new_mem_startup,
- RES, size,
- True /* readable? */,
- False /* writable? */,
- False /* executable? */,
- 0 /* di_handle */);
- }
+ VG_(change_mapping_ownership)(RES, False);
}
#endif /* SOLARIS_GETZONEOFFSET_FASTTRAP */
extern void VG_(restore_context)(ThreadId tid, vki_ucontext_t *uc,
CorePart part, Bool esp_is_thrptr);
extern void VG_(syswrap_init)(void);
+extern void VG_(change_mapping_ownership)(Addr addr, Bool once_only);
extern Bool VG_(setup_client_dataseg)(void);
extern void VG_(track_client_dataseg)(ThreadId tid);
#endif
#include <sys/types.h>
#define VKI_UINT_MAX UINT_MAX
+#define VKI_UINTPTR_MAX UINTPTR_MAX
#define vki_boolean_t boolean_t
#define vki_datalink_id_t datalink_id_t
#define vki_uint_t uint_t
#define VKI_AT_SUN_HWCAP AT_SUN_HWCAP
#define VKI_AT_SUN_EXECNAME AT_SUN_EXECNAME
#define VKI_AT_SUN_AUXFLAGS AT_SUN_AUXFLAGS
+#if defined(SOLARIS_RESERVE_SYSSTAT_ADDR)
+#define VKI_AT_SUN_SYSSTAT_ADDR AT_SUN_SYSSTAT_ADDR
+#endif
+#if defined(SOLARIS_RESERVE_SYSSTAT_ZONE_ADDR)
+#define VKI_AT_SUN_SYSSTAT_ZONE_ADDR AT_SUN_SYSSTAT_ZONE_ADDR
+#endif
#define VKI_AF_SUN_HWCAPVERIFY AF_SUN_HWCAPVERIFY