]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Support correctly AT_SUN_SYSSTAT_ADDR and AT_SUN_SYSSTAT_ZONE_ADDR
authorIvo Raisr <ivosh@ivosh.net>
Fri, 25 Sep 2015 20:12:26 +0000 (20:12 +0000)
committerIvo Raisr <ivosh@ivosh.net>
Fri, 25 Sep 2015 20:12:26 +0000 (20:12 +0000)
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

README.solaris
coregrind/m_initimg/initimg-solaris.c
coregrind/m_syswrap/syswrap-solaris.c
coregrind/pub_core_syswrap.h
include/vki/vki-solaris.h

index 6bc8eec4a578409cf1a451eb0bfea990d1d03b4d..a4aaf6a22ba5f45dde29aafe6fc3854796a33280 100644 (file)
@@ -79,15 +79,6 @@ Limitations
   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
@@ -139,6 +130,7 @@ TODO list
   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
index bdfb6c5459aebf73534c9725a2d07b51ef5ee214..2c20e21767a6bf5d0602b67ab9df8c956dde53c7 100644 (file)
@@ -29,6 +29,8 @@
    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. */
@@ -273,6 +275,59 @@ static HChar *copy_str(HChar **tab, const HChar *str)
    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.
@@ -305,11 +360,12 @@ static HChar *copy_str(HChar **tab, const HChar *str)
    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,
@@ -335,6 +391,9 @@ static Addr setup_client_stack(void *init_sp,
    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. */
@@ -378,11 +437,20 @@ static Addr setup_client_stack(void *init_sp,
       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;
@@ -739,6 +807,22 @@ static Addr setup_client_stack(void *init_sp,
        */
    }
 
+#  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;
@@ -811,7 +895,7 @@ IIFinaliseImageInfo VG_(ii_create_image)(IICreateImageInfo iicii,
          - 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;
index 25029d4d1d205ee581cf6f04040eda878ef6b59f..bd2f0044c4dcad2bd45397dc5449ba7c38fca232 100644 (file)
    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)
@@ -438,6 +438,50 @@ void VG_(syswrap_init)(void)
    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)
 {
@@ -9755,33 +9799,7 @@ POST(fast_gethrt)
    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 */
 
@@ -9798,33 +9816,7 @@ POST(fast_getzoneoffset)
    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 */
 
index 35e8bc915e63f5ed1eecaf2e521ff3d6907b3ee4..0b5b54bd6bd4bc33f4e029f63ebb133658e99e7f 100644 (file)
@@ -93,6 +93,7 @@ extern void VG_(save_context)(ThreadId tid, vki_ucontext_t *uc,
 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
index a5f7ece5b8300df4112a748d00c08dd907b90a21..7b5a6a05f624b0b8d5d95a86ecb45b982d0baa61 100644 (file)
@@ -70,6 +70,7 @@
 
 #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
@@ -252,6 +253,12 @@ typedef struct {
 #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