aboutsummaryrefslogtreecommitdiff
path: root/coregrind/m_syswrap
diff options
context:
space:
mode:
authoriraisr <iraisr@a5019735-40e9-0310-863c-91ae7b9d1cf9>2015-08-20 20:25:19 +0000
committeriraisr <iraisr@a5019735-40e9-0310-863c-91ae7b9d1cf9>2015-08-20 20:25:19 +0000
commit1c628f3016f3437eda3294da1df7fcedef96d1d9 (patch)
tree49ef9c5064f3d2fb8fa809051d9342cd2f7f7888 /coregrind/m_syswrap
parentf27835c744993697c6938da5489625af88771457 (diff)
downloadvalgrind-1c628f3016f3437eda3294da1df7fcedef96d1d9.tar.gz
Initial data (brk) segment is setup on demand, when a first brk() syscall
is made. It cannot be established during client image initialization because that 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. Preparatory work for ldsoexec support. n-i-bz git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15572 a5019735-40e9-0310-863c-91ae7b9d1cf9
Diffstat (limited to 'coregrind/m_syswrap')
-rw-r--r--coregrind/m_syswrap/syswrap-solaris.c100
1 files changed, 92 insertions, 8 deletions
diff --git a/coregrind/m_syswrap/syswrap-solaris.c b/coregrind/m_syswrap/syswrap-solaris.c
index d1f010c9e..4ea2463f4 100644
--- a/coregrind/m_syswrap/syswrap-solaris.c
+++ b/coregrind/m_syswrap/syswrap-solaris.c
@@ -1803,15 +1803,18 @@ PRE(sys_time)
PRE_REG_READ0(long, "time");
}
-/* Data segment for brk (heap).
- Initial data segment is established during image initialization
- (initimg-solaris.c). Notable facts:
+/* 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).
+ Notable facts:
- VG_(brk_base) is not page aligned; does not move
- VG_(brk_limit) moves between [VG_(brk_base), data segment end]
- data segment end is always page aligned
- right after data segment end is 1-page reservation
- | heap |
+ | heap | 1 page
+------+------+--------------+-------+
| BSS | anon | anon | resvn |
+------+------+--------------+-------+
@@ -1824,9 +1827,63 @@ PRE(sys_time)
VG_(brk_base) -- not page aligned -- does not move
Because VG_(brk_base) is not page-aligned and is initially located within
- pre-established data segment, special care has to be taken in the code below
- to handle this feature.
-*/
+ pre-established BSS (data) segment, special care has to be taken in the code
+ below to handle this feature.
+
+ Reservation segment is used to protect the data segment merging with
+ a pre-existing segment. This should be no problem because address space
+ manager ensures that requests for client address space are satisfied from
+ the highest available addresses. However when memory is low, data segment
+ can meet with mmap'ed objects and the reservation segment separates these.
+ 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. */
+
+/* Establishes initial data segment for brk (heap). */
+static Bool setup_client_dataseg(SizeT initial_size, ThreadId tid)
+{
+ Addr anon_start = VG_PGROUNDUP(VG_(brk_base));
+ SizeT anon_size = VG_PGROUNDUP(initial_size);
+ Addr resvn_start = anon_start + anon_size;
+ SizeT resvn_size = VKI_PAGE_SIZE;
+
+ vg_assert(VG_IS_PAGE_ALIGNED(anon_size));
+ vg_assert(VG_IS_PAGE_ALIGNED(resvn_size));
+ vg_assert(VG_IS_PAGE_ALIGNED(anon_start));
+ vg_assert(VG_IS_PAGE_ALIGNED(resvn_start));
+ vg_assert(VG_(brk_base) == VG_(brk_limit));
+
+ /* Find the loaded data segment and remember its protection. */
+ const NSegment *seg = VG_(am_find_nsegment)(VG_(brk_base) - 1);
+ vg_assert(seg != NULL);
+ UInt prot = (seg->hasR ? VKI_PROT_READ : 0)
+ | (seg->hasW ? VKI_PROT_WRITE : 0)
+ | (seg->hasX ? VKI_PROT_EXEC : 0);
+
+ /* Try to create the data segment and associated reservation where
+ VG_(brk_base) says. */
+ Bool ok = VG_(am_create_reservation)(resvn_start, resvn_size, SmLower,
+ anon_size);
+ if (!ok) {
+ /* That didn't work, we're hosed. */
+ return False;
+ }
+
+ /* Map the data segment. */
+ SysRes sres = VG_(am_mmap_anon_fixed_client)(anon_start, anon_size, prot);
+ 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);
+ 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)
{
@@ -1845,7 +1902,7 @@ PRE(sys_brk)
PRINT("sys_brk ( %#lx )", ARG1);
PRE_REG_READ1(unsigned long, "brk", vki_caddr_t, end_data_segment);
- if (!new_brk) {
+ if (new_brk == 0) {
/* brk(0) - specific to Solaris 11 only. */
SET_STATUS_Success(old_brk_limit);
return;
@@ -1866,6 +1923,33 @@ PRE(sys_brk)
return;
}
+ 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)) {
+ 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;
+ }
+
if (new_brk < old_brk_limit) {
/* Shrinking the data segment. Be lazy and don't munmap the excess
area. */