mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-03 18:13:01 +00:00
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
This commit is contained in:
parent
8372cfdb0f
commit
542fa886dc
@ -747,63 +747,6 @@ static Addr setup_client_stack(void *init_sp,
|
||||
return client_SP;
|
||||
}
|
||||
|
||||
|
||||
/* Allocate the client data segment. 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.
|
||||
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.
|
||||
See the brk syscall wrapper for more information. */
|
||||
static void setup_client_dataseg(SizeT initial_size)
|
||||
{
|
||||
Bool ok;
|
||||
SysRes sres;
|
||||
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;
|
||||
const NSegment *seg;
|
||||
UInt prot;
|
||||
|
||||
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));
|
||||
|
||||
/* Stay sane (because there's been no brk activity yet). */
|
||||
vg_assert(VG_(brk_base) == VG_(brk_limit));
|
||||
|
||||
/* Find the loaded data segment and remember its protection. */
|
||||
seg = VG_(am_find_nsegment)(VG_(brk_base) - 1);
|
||||
vg_assert(seg);
|
||||
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. */
|
||||
ok = VG_(am_create_reservation)(resvn_start, resvn_size, SmLower, anon_size);
|
||||
if (!ok) {
|
||||
/* That didn't work, we're hosed. */
|
||||
VG_(printf)("valgrind: cannot initialize a brk segment\n");
|
||||
VG_(exit)(1);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
vg_assert(ok);
|
||||
|
||||
/* Map the data segment. */
|
||||
sres = VG_(am_mmap_anon_fixed_client)(anon_start, anon_size, prot);
|
||||
vg_assert(!sr_isError(sres));
|
||||
vg_assert(sr_Res(sres) == anon_start);
|
||||
}
|
||||
|
||||
|
||||
/*====================================================================*/
|
||||
/*=== TOP-LEVEL: VG_(setup_client_initial_image) ===*/
|
||||
/*====================================================================*/
|
||||
@ -898,26 +841,10 @@ IIFinaliseImageInfo VG_(ii_create_image)(IICreateImageInfo iicii,
|
||||
iifii.clstack_max_size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Setup client data (brk) segment. Initially segment at least
|
||||
// 1 MB and at most 8 MB large which abuts a 1-page reservation.
|
||||
// p: load_client() [for 'info' and hence VG_(brk_base)]
|
||||
//--------------------------------------------------------------
|
||||
{
|
||||
SizeT m1 = 1024 * 1024;
|
||||
SizeT m8 = 8 * m1;
|
||||
SizeT dseg_max_size = VG_(client_rlimit_data).rlim_cur;
|
||||
VG_(debugLog)(1, "initimg", "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);
|
||||
|
||||
setup_client_dataseg(dseg_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. */
|
||||
return iifii;
|
||||
}
|
||||
|
||||
@ -934,7 +861,6 @@ IIFinaliseImageInfo VG_(ii_create_image)(IICreateImageInfo iicii,
|
||||
void VG_(ii_finalise_image)(IIFinaliseImageInfo iifii)
|
||||
{
|
||||
ThreadArchState *arch = &VG_(threads)[1].arch;
|
||||
const NSegment *seg;
|
||||
|
||||
# if defined(VGA_x86)
|
||||
vg_assert(0 == sizeof(VexGuestX86State) % LibVEX_GUEST_STATE_ALIGN);
|
||||
@ -990,14 +916,16 @@ void VG_(ii_finalise_image)(IIFinaliseImageInfo iifii)
|
||||
VG_TRACK(post_reg_write, Vg_CoreStartup, 1/*tid*/, 0/*offset*/,
|
||||
sizeof(VexGuestArchState));
|
||||
|
||||
/* Tell the tool about the client data segment and then kill it which will
|
||||
make it inaccessible/unaddressable. */
|
||||
seg = VG_(am_find_nsegment)(VG_PGROUNDUP(VG_(brk_base)));
|
||||
vg_assert(seg);
|
||||
vg_assert(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));
|
||||
/* 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));
|
||||
}
|
||||
}
|
||||
|
||||
#endif // defined(VGO_solaris)
|
||||
|
||||
@ -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. */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user