diff options
author | iraisr <iraisr@a5019735-40e9-0310-863c-91ae7b9d1cf9> | 2015-08-20 20:25:19 +0000 |
---|---|---|
committer | iraisr <iraisr@a5019735-40e9-0310-863c-91ae7b9d1cf9> | 2015-08-20 20:25:19 +0000 |
commit | 1c628f3016f3437eda3294da1df7fcedef96d1d9 (patch) | |
tree | 49ef9c5064f3d2fb8fa809051d9342cd2f7f7888 /coregrind/m_syswrap | |
parent | f27835c744993697c6938da5489625af88771457 (diff) | |
download | valgrind-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.c | 100 |
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. */ |