]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Distinguish properly when to establish the client data segment.
authorIvo Raisr <ivosh@ivosh.net>
Sat, 22 Aug 2015 22:08:43 +0000 (22:08 +0000)
committerIvo Raisr <ivosh@ivosh.net>
Sat, 22 Aug 2015 22:08:43 +0000 (22:08 +0000)
Initial data segment is established (see initimg-solaris.c for rationale):
- directly during client program image initialization,
- or on demand when the executed program is the runtime linker itself,
  after it has loaded its target dynamic executable (see PRE(sys_mmapobj)),
  or when the first brk() syscall is made.

More preparatory work for ldsoexec support.
n-i-bz

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15583

coregrind/m_initimg/initimg-solaris.c
coregrind/m_syswrap/syswrap-solaris.c
coregrind/m_ume/elf.c
coregrind/pub_core_syswrap.h
coregrind/pub_core_ume.h

index 20b02d18a7d7e5ddaf9156b1f61733db7daddfa5..bdfb6c5459aebf73534c9725a2d07b51ef5ee214 100644 (file)
@@ -48,6 +48,7 @@
 #include "pub_core_machine.h"
 #include "pub_core_ume.h"
 #include "pub_core_options.h"
+#include "pub_core_syswrap.h"
 #include "pub_core_tooliface.h"       /* VG_TRACK */
 #include "pub_core_threadstate.h"     /* ThreadArchState */
 #include "priv_initimg_pathscan.h"
@@ -102,7 +103,11 @@ static void load_client(/*OUT*/ExeInfo *info,
       VG_(cl_exec_fd) = sr_Res(res);
 
    /* Set initial brk values. */
-   VG_(brk_base) = VG_(brk_limit) = info->brkbase;
+   if (info->ldsoexec) {
+      VG_(brk_base) = VG_(brk_limit) = -1;
+   } else {
+      VG_(brk_base) = VG_(brk_limit) = info->brkbase;
+   }
 }
 
 
@@ -841,10 +846,20 @@ IIFinaliseImageInfo VG_(ii_create_image)(IICreateImageInfo iicii,
                        iifii.clstack_max_size);
    }
 
-   /* Initial data (brk) segment is setup on demand, when a first brk() syscall
-      is made. It cannot be established now because it would conflict with
-      a temporary stack which ld.so.1 (when executed directly) uses for loading
-      the target dynamic executable. See PRE(sys_brk) in syswrap-solaris.c. */
+   if (info.ldsoexec) {
+      /* We are executing the runtime linker itself.
+         Initial data (brk) segment is setup on demand, after the target dynamic
+         executable has been loaded or when a first brk() syscall is made.
+         It cannot be established now because it would conflict with a temporary
+         stack which ld.so.1 (when executed directly) uses for loading the
+         target dynamic executable. See PRE(sys_brk) in syswrap-solaris.c. */
+   } else {
+      if (!VG_(setup_client_dataseg)()) {
+         VG_(printf)("valgrind: cannot initialize data segment (brk).\n");
+         VG_(exit)(1);
+      }
+   }
+
    return iifii;
 }
 
@@ -916,15 +931,10 @@ void VG_(ii_finalise_image)(IIFinaliseImageInfo iifii)
    VG_TRACK(post_reg_write, Vg_CoreStartup, 1/*tid*/, 0/*offset*/,
             sizeof(VexGuestArchState));
 
-   /* Make inaccessible/unaddressable the end of the client data segment.
-      See PRE(sys_brk) in syswrap-solaris.c for details. Nothing to do in
-      case VG_(brk_base) starts on the beginning of a free page. */
-   const NSegment *seg = VG_(am_find_nsegment)(VG_(brk_base));
-   if (seg != NULL) {
-      vg_assert((seg->kind == SkFileC) || (seg->kind == SkAnonC));
-      VG_TRACK(new_mem_brk, VG_(brk_base), seg->end + 1 - VG_(brk_base),
-               1 /* tid */);
-      VG_TRACK(die_mem_brk, VG_(brk_base), seg->end + 1 - VG_(brk_base));
+   if (VG_(brk_base) != -1 ) {
+      /* Make inaccessible/unaddressable the end of the client data segment.
+         See PRE(sys_brk) in syswrap-solaris.c for details. */
+      VG_(track_client_dataseg)(1 /* tid */);
    }
 }
 
index 4ea2463f457c41427dfc7cedffda8ebfbd6a1d96..54ad280f87b78e0d02eabaa738b5586d56ccf316 100644 (file)
@@ -1806,8 +1806,13 @@ PRE(sys_time)
 /* Data segment for brk (heap). It is an expandable anonymous mapping
    abutting a 1-page reservation. The data segment starts at VG_(brk_base)
    and runs up to VG_(brk_limit). None of these two values have to be
-   page-aligned. Initial data segment is established on demand here (see
-   initimg-solaris.c for rationale).
+   page-aligned.
+   Initial data segment is established (see initimg-solaris.c for rationale):
+   - directly during client program image initialization,
+   - or on demand when the executed program is the runtime linker itself,
+     after it has loaded its target dynamic executable (see PRE(sys_mmapobj)),
+     or when the first brk() syscall is made.
+
    Notable facts:
    - VG_(brk_base) is not page aligned; does not move
    - VG_(brk_limit) moves between [VG_(brk_base), data segment end]
@@ -1838,9 +1843,23 @@ PRE(sys_time)
    The page that contains VG_(brk_base) is already allocated by the program's
    loaded data segment. The brk syscall wrapper handles this special case. */
 
+static Bool brk_segment_established = False;
+
 /* Establishes initial data segment for brk (heap). */
-static Bool setup_client_dataseg(SizeT initial_size, ThreadId tid)
-{
+Bool VG_(setup_client_dataseg)(void)
+{
+   /* Segment size is initially at least 1 MB and at most 8 MB. */
+   SizeT m1 = 1024 * 1024;
+   SizeT m8 = 8 * m1;
+   SizeT initial_size = VG_(client_rlimit_data).rlim_cur;
+   VG_(debugLog)(1, "syswrap-solaris", "Setup client data (brk) segment "
+                                       "at %#lx\n", VG_(brk_base));
+   if (initial_size < m1)
+      initial_size = m1;
+   if (initial_size > m8)
+      initial_size = m8;
+   initial_size = VG_PGROUNDUP(initial_size);
+
    Addr anon_start = VG_PGROUNDUP(VG_(brk_base));
    SizeT anon_size = VG_PGROUNDUP(initial_size);
    Addr resvn_start = anon_start + anon_size;
@@ -1873,18 +1892,22 @@ static Bool setup_client_dataseg(SizeT initial_size, ThreadId tid)
    vg_assert(!sr_isError(sres));
    vg_assert(sr_Res(sres) == anon_start);
 
-   /* Tell the tool about the client data segment and then kill it which will
-      make it initially inaccessible/unaddressable. */
-   seg = VG_(am_find_nsegment)(anon_start);
+   brk_segment_established = True;
+   return True;
+}
+
+/* Tell the tool about the client data segment and then kill it which will
+   make it initially inaccessible/unaddressable. */
+void VG_(track_client_dataseg)(ThreadId tid)
+{
+   const NSegment *seg = VG_(am_find_nsegment)(VG_PGROUNDUP(VG_(brk_base)));
    vg_assert(seg != NULL);
    vg_assert(seg->kind == SkAnonC);
+
    VG_TRACK(new_mem_brk, VG_(brk_base), seg->end + 1 - VG_(brk_base), tid);
    VG_TRACK(die_mem_brk, VG_(brk_base), seg->end + 1 - VG_(brk_base));
-   return True;
 }
 
-static Bool brk_segment_established = False;
-
 PRE(sys_brk)
 {
    /* unsigned long brk(caddr_t end_data_segment); */
@@ -1923,31 +1946,22 @@ PRE(sys_brk)
       return;
    }
 
+   /* The brk base and limit must have been already set. */
+   vg_assert(VG_(brk_base) != -1);
+   vg_assert(VG_(brk_limit) != -1);
+
    if (!brk_segment_established) {
       /* Stay sane (because there should have been no brk activity yet). */
       vg_assert(VG_(brk_base) == VG_(brk_limit));
 
-      /* Establish an initial data segment for brk (heap).
-         Initially at least 1 MB and at most 8 MB large. */
-      SizeT m1 = 1024 * 1024;
-      SizeT m8 = 8 * m1;
-      SizeT dseg_max_size = VG_(client_rlimit_data).rlim_cur;
-      VG_(debugLog)(1, "syswrap-solaris", "Setup client data (brk) segment "
-                                          "at %#lx\n", VG_(brk_base));
-      if (dseg_max_size < m1)
-         dseg_max_size = m1;
-      if (dseg_max_size > m8)
-         dseg_max_size = m8;
-      dseg_max_size = VG_PGROUNDUP(dseg_max_size);
-
-      if (!setup_client_dataseg(dseg_max_size, tid)) {
+      if (!VG_(setup_client_dataseg)()) {
          VG_(umsg)("Cannot map memory to initialize brk segment in thread #%d "
                    "at %#lx\n", tid, VG_(brk_base));
          SET_STATUS_Failure(VKI_ENOMEM);
          return;
       }
 
-      brk_segment_established = True;
+      VG_(track_client_dataseg)(tid);
    }
 
    if (new_brk < old_brk_limit) {
index 78a22f2b9721ed098fb698d3a09939b275d55b2b..a9871501fd28d0ff2f4fc62d381184046a3459bc 100644 (file)
@@ -563,9 +563,15 @@ Int VG_(load_ELF)(Int fd, const HChar* name, /*MOD*/ExeInfo* info)
 
       VG_(free)(interp->p);
       VG_(free)(interp);
-   } else
+   } else {
       entry = (void *)(ebase + e->e.e_entry);
 
+#     if defined(VGO_solaris)
+      if (e->e.e_type == ET_DYN)
+         info->ldsoexec = True;
+#     endif
+   }
+
    info->exe_base = minaddr + ebase;
    info->exe_end  = maxaddr + ebase;
 
index 2508b28c08361fc93dfa9beb4a4ef3bd67605b79..35e8bc915e63f5ed1eecaf2e521ff3d6907b3ee4 100644 (file)
@@ -93,6 +93,8 @@ 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 Bool VG_(setup_client_dataseg)(void);
+extern void VG_(track_client_dataseg)(ThreadId tid);
 #endif
 
 #endif   // __PUB_CORE_SYSWRAP_H
index 856069e92c785625d1fa016292463dee09b98249..d9e459c59441e19e67a6431736aa41cd7b2938f3 100644 (file)
@@ -67,6 +67,7 @@ typedef
 #if defined(VGO_solaris)
       Addr  init_thrptr;       // OUT: architecture-specific user per-thread location
       Bool  real_phdr_present; // OUT: PT_PHDR found, include phdr in auxv
+      Bool  ldsoexec;          // OUT: the program is the runtime linker itself
 #endif
 
       Addr entry;        // OUT: entrypoint in main executable