|
From: <sv...@va...> - 2005-09-14 12:11:40
|
Author: sewardj
Date: 2005-09-14 13:11:37 +0100 (Wed, 14 Sep 2005)
New Revision: 4654
Log:
Redo the way segment splitting is done, to be simpler and general and
to make it possible to handle mprotect properly. Reimplement
add_segment() as a result.
Modified:
branches/ASPACEM/coregrind/m_aspacemgr/aspacemgr.c
Modified: branches/ASPACEM/coregrind/m_aspacemgr/aspacemgr.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- branches/ASPACEM/coregrind/m_aspacemgr/aspacemgr.c 2005-09-14 08:12:0=
5 UTC (rev 4653)
+++ branches/ASPACEM/coregrind/m_aspacemgr/aspacemgr.c 2005-09-14 12:11:3=
7 UTC (rev 4654)
@@ -1521,6 +1521,7 @@
//--------------------------------------------------------------
// Functions for extracting information about file descriptors.
=20
+/* Extract the device and inode numbers for a fd. */
static=20
Bool get_inode_for_fd ( Int fd, /*OUT*/UInt* dev, /*OUT*/UInt* ino )
{
@@ -1987,127 +1988,108 @@
/*--- ---*/
/*-----------------------------------------------------------------*/
=20
-/* Helper fn */
+/* Split the segment containing 'a' into two, so that 'a' is
+ guaranteed to be the start of a new segment. If 'a' is already the
+ start of a segment, do nothing. */
=20
-static Bool is_SkFile ( SegKind sk )
+static void split_nsegment_at ( Addr a )
{
- return sk =3D=3D SkFileV || sk =3D=3D SkFileC;
-}
+ Int i, j;
=20
+ aspacem_assert(a > 0);
+ aspacem_assert(VG_IS_PAGE_ALIGNED(a));
+=20
+ i =3D find_nsegment_idx(a);
+ aspacem_assert(i >=3D 0 && i < nsegments_used);
=20
-/* Add SEG to the collection, deleting/truncating any it overlaps.
- This deals with all the tricky cases of splitting up segments as
- needed. */
+ if (nsegments[i].start =3D=3D a)
+ /* 'a' is already the start point of a segment, so nothing to be
+ done. */
+ return;
=20
-static void add_segment ( NSegment* seg )
-{
- Int nDeld, i, j, k;
- Addr iStart, iEnd;
+ /* else we have to slide the segments upwards to make a hole */
+ if (nsegments_used >=3D VG_N_SEGMENTS)
+ aspacem_barf_toolow("VG_N_SEGMENTS");
+ for (j =3D nsegments_used-1; j > i; j--)
+ nsegments[j+1] =3D nsegments[j];
+ nsegments_used++;
=20
- Addr dStart =3D seg->start;
- Addr dEnd =3D seg->end;
+ nsegments[i+1] =3D nsegments[i];
+ nsegments[i+1].start =3D a;
+ nsegments[i].end =3D a-1;
=20
- aspacem_assert(dStart <=3D dEnd);
- aspacem_assert(VG_IS_PAGE_ALIGNED(dStart));
- aspacem_assert(VG_IS_PAGE_ALIGNED(dEnd+1));
- aspacem_assert(sane_NSegment(seg));
+ if (nsegments[i].kind =3D=3D SkFileV || nsegments[i].kind =3D=3D SkFi=
leC)
+ nsegments[i+1].offset=20
+ +=3D ((ULong)nsegments[i+1].start) - ((ULong)nsegments[i].start=
);
=20
- nDeld =3D 0;
+ aspacem_assert(sane_NSegment(&nsegments[i]));
+ aspacem_assert(sane_NSegment(&nsegments[i+1]));
+}
=20
- /* Iterate over all segments, considering how each interacts with
- the new address range dStart .. dEnd. */
=20
- for (i =3D 0; i < nsegments_used; i++) {
+/* Do the minimum amount of segment splitting necessary to ensure that
+ sLo is the first address denoted by some segment and sHi is the
+ highest address denoted by some other segment. Returns the indices
+ of the lowest and highest segments in the range. */
=20
- nsegments[i].mark =3D False;
+static=20
+void split_nsegments_lo_and_hi ( Addr sLo, Addr sHi,
+ /*OUT*/Int* iLo,
+ /*OUT*/Int* iHi )
+{
+ aspacem_assert(sLo < sHi);
+ aspacem_assert(VG_IS_PAGE_ALIGNED(sLo));
+ aspacem_assert(VG_IS_PAGE_ALIGNED(sHi+1));
=20
- iStart =3D nsegments[i].start;
- iEnd =3D nsegments[i].end;
+ if (sLo > 0)
+ split_nsegment_at(sLo);
+ if (sHi < sHi+1)
+ split_nsegment_at(sHi+1);
=20
- /* no-overlap cases */
- if (iEnd < dStart) continue;
- if (dEnd < iStart) continue;
+ *iLo =3D find_nsegment_idx(sLo);
+ *iHi =3D find_nsegment_idx(sHi);
+ aspacem_assert(0 <=3D *iLo && *iLo < nsegments_used);
+ aspacem_assert(0 <=3D *iHi && *iHi < nsegments_used);
+ aspacem_assert(*iLo <=3D *iHi);
+ aspacem_assert(nsegments[*iLo].start =3D=3D sLo);
+ aspacem_assert(nsegments[*iHi].end =3D=3D sHi);
+ /* Not that I'm overly paranoid or anything, definitely not :-) */
+}
=20
- if (dStart <=3D iStart && iEnd <=3D dEnd) {
- /* i is completely overlapped. Mark it for deletion. */
- nsegments[i].mark =3D True;
- nDeld++;
- continue;
- }
=20
- if (iStart < dStart && iEnd > dEnd) {
- /* deleted interval is completely contained within i. This
- means i has to be split into two pieces. As a result,
- first move the following elements up by one place to make
- space for the new part. */
- if (nsegments_used >=3D VG_N_SEGMENTS)
- aspacem_barf_toolow("VG_N_SEGMENTS");
- for (j =3D nsegments_used-1; j > i; j--)
- nsegments[j+1] =3D nsegments[j];
- nsegments_used++;
- nsegments[i+1] =3D nsegments[i];
- nsegments[i].end =3D dStart-1;
- nsegments[i+1].start =3D dEnd+1;
- if (is_SkFile(nsegments[i].kind))
- nsegments[i+1].offset +=3D (nsegments[i+1].start - nsegments=
[i].start);
- continue;
- }
+/* Add SEG to the collection, deleting/truncating any it overlaps.
+ This deals with all the tricky cases of splitting up segments as
+ needed. */
=20
- if (iStart < dStart && iEnd <=3D dEnd && iEnd >=3D dStart) {
- /* interval to be deleted straddles upper boundary of i. */
- nsegments[i].end =3D dStart-1;
- continue;
- }
+static void add_segment ( NSegment* seg )
+{
+ Int i, iLo, iHi, delta;
=20
- if (iEnd > dEnd && iStart >=3D dStart && iStart <=3D dEnd) {
- /* interval to be deleted straddles lower boundary of i. */
- if (is_SkFile(nsegments[i].kind))
- nsegments[i].offset +=3D (dEnd+1 - nsegments[i].start);
- nsegments[i].start =3D dEnd+1;
- continue;
- }
+ Addr sStart =3D seg->start;
+ Addr sEnd =3D seg->end;
=20
- /* I don't think we can get here. */
- aspacem_assert(0);
- }
+ aspacem_assert(sStart <=3D sEnd);
+ aspacem_assert(VG_IS_PAGE_ALIGNED(sStart));
+ aspacem_assert(VG_IS_PAGE_ALIGNED(sEnd+1));
+ aspacem_assert(sane_NSegment(seg));
=20
- /* Get rid of the intervals marked for deletion. */
- if (nDeld > 0) {
- j =3D 0;
- for (i =3D 0; i < nsegments_used; i++) {
- if (nsegments[i].mark)
- continue;
- nsegments[j] =3D nsegments[i];
- j++;
- }
- nsegments_used -=3D nDeld;
- }
+ split_nsegments_lo_and_hi( sStart, sEnd, &iLo, &iHi );
=20
- /* At this point, there should be a gap dStart .. dEnd inclusive.
- Find the gap and insert the new interval in it. Set k so that
- all entries >=3D k must be moved up 1, and the new interval placed
- at k. */
- if (nsegments_used >=3D VG_N_SEGMENTS)
- aspacem_barf_toolow("VG_N_SEGMENTS");
- if (nsegments_used =3D=3D 0) {
- k =3D 0;
- } else {
- for (i =3D 0; i < nsegments_used; i++) {
- if (dEnd+1 =3D=3D nsegments[i].start=20
- && /*guard against wraparound*/dEnd+1 > dEnd)
- break;
- }
- k =3D i;
+ /* Now iLo .. iHi inclusive is the range of segment indices which
+ seg will replace. If we're replacing more than one segment,
+ slide those above the range down to fill the hole. */
+ delta =3D iHi - iLo;
+ aspacem_assert(delta >=3D 0);
+ if (delta > 0) {
+ for (i =3D iLo; i < nsegments_used-delta; i++)
+ nsegments[i] =3D nsegments[i+delta];
+ nsegments_used -=3D delta;
}
=20
- aspacem_assert(k >=3D 0 && k <=3D nsegments_used);
- for (j =3D nsegments_used-1; j >=3D k; j--)
- nsegments[j+1] =3D nsegments[j];
- nsegments_used++;
+ nsegments[iLo] =3D *seg;
=20
- nsegments[k] =3D *seg;
-
preen_nsegments();
+ if (0) VG_(am_show_nsegments)(0,"AFTER preen (add_segment)");
}
=20
=20
@@ -2523,10 +2505,15 @@
nsegments[iLo].hasR =3D toBool(prot & VKI_PROT_READ);
nsegments[iLo].hasW =3D toBool(prot & VKI_PROT_WRITE);
nsegments[iLo].hasX =3D toBool(prot & VKI_PROT_EXEC);
+ preen_nsegments();
return;
}
=20
/* FIXME: unhandled general case */
+ if (1)
+ VG_(debugLog)(0,"aspacem", "notify mprotect 0x%llx %lld\n",=20
+ (ULong)start, (Long)len);
+ VG_(am_show_nsegments)(0, "notify_mprotect general case");
aspacem_barf("notify_mprotect general case");
}
=20
|