On 06/04/2010 02:12 PM, Arun Sharma wrote:
On Thu, Jun 3, 2010 at 6:19 PM, Jason Evans<[email protected]> wrote:
I have been testing recent versions of libunwind on Centos 5.2 (x86_64) [...]
The "address crossing page boundary" problem is orthogonal to which
API is used and was not a reason in itself for accepting the patch
which switched the default to mincore on Linux.
The mincore code doesn't get the "address crossing page boundary"
problem right anyway, so it's good that other criteria were used. ;-)
I'd be happy to take a patch to msync() that addresses the page
crossing problem and reconsider the choice between mincore vs msync if
there is a good test case to show one is better than the other.
I don't particularly care whether libunwind uses msync or mincore, but
right now most of libunwind's regression tests fail for me, and if I use
libunwind for backtracing, I get segfaults. The attached patch fixes
the regression for me. If you prefer not to fix the problem in this
fashion, hopefully the patch will at least prove useful in
characterizing the problem.
Thanks,
Jason
>From e7ec75f623c07718c4caf2b157d6763ff14d63f2 Mon Sep 17 00:00:00 2001
From: Jason Evans <[email protected]>
Date: Fri, 4 Jun 2010 12:55:46 -0700
Subject: [PATCH] Modify mincore(2)-based validate_mem() checks.
Verify that if mincore(2) claims a word is unmapped, msync(2) agrees.
Also check for EAGAIN errors from mincore(2), as required on Linux.
Fix both mincore(2) and msync(2) calls to properly handle unaligned
words that straddle page boundaries.
---
src/x86/Ginit.c | 32 +++++++++++++++++++++++++++++---
src/x86_64/Ginit.c | 31 ++++++++++++++++++++++++++++---
2 files changed, 57 insertions(+), 6 deletions(-)
diff --git a/src/x86/Ginit.c b/src/x86/Ginit.c
index 0af616a..f4189e7 100644
--- a/src/x86/Ginit.c
+++ b/src/x86/Ginit.c
@@ -30,6 +30,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <stdlib.h>
#include <string.h>
+#include <sys/mman.h>
+#ifdef HAVE_MINCORE
+#include <errno.h>
+#endif
#include "unwind_i.h"
@@ -90,6 +94,12 @@ validate_mem (unw_word_t addr)
#ifdef HAVE_MINCORE
char mvec[2]; /* Unaligned access may cross page boundary */
#endif
+ size_t len;
+
+ if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr))
+ len = PAGE_SIZE;
+ else
+ len = PAGE_SIZE * 2;
addr = PAGE_START(addr);
@@ -103,11 +113,27 @@ validate_mem (unw_word_t addr)
}
#ifdef HAVE_MINCORE
- if (mincore ((void *) addr, sizeof (unw_word_t), mvec) == -1)
+ while (1)
+ {
+ if (mincore ((void *) addr, len, mvec) == 0)
+ break;
+ switch (errno)
+ {
+ case EAGAIN: break;
+ case ENOMEM:
+ /* mincore() doesn't always agree with msync() on Linux, so make
+ sure that msync() also thinks addr is not mapped. */
+ if (msync ((void *) addr, len, MS_ASYNC) != -1)
+ goto MINCORE_OUT;
+ return -1;
+ case EFAULT: case EINVAL: default: abort ();
+ }
+ }
+MINCORE_OUT:
#else
- if (msync ((void *) addr, sizeof (unw_word_t), MS_ASYNC) == -1)
-#endif
+ if (msync ((void *) addr, len, MS_ASYNC) == -1)
return -1;
+#endif
victim = lga_victim;
for (i = 0; i < NLGA; i++) {
diff --git a/src/x86_64/Ginit.c b/src/x86_64/Ginit.c
index 14614f1..babb002 100644
--- a/src/x86_64/Ginit.c
+++ b/src/x86_64/Ginit.c
@@ -33,6 +33,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+#ifdef HAVE_MINCORE
+#include <errno.h>
+#endif
#include "unwind_i.h"
@@ -93,6 +96,12 @@ validate_mem (unw_word_t addr)
#ifdef HAVE_MINCORE
char mvec[2]; /* Unaligned access may cross page boundary */
#endif
+ size_t len;
+
+ if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr))
+ len = PAGE_SIZE;
+ else
+ len = PAGE_SIZE * 2;
addr = PAGE_START(addr);
@@ -106,11 +115,27 @@ validate_mem (unw_word_t addr)
}
#ifdef HAVE_MINCORE
- if (mincore ((void *) addr, sizeof (unw_word_t), mvec) == -1)
+ while (1)
+ {
+ if (mincore ((void *) addr, len, mvec) == 0)
+ break;
+ switch (errno)
+ {
+ case EAGAIN: break;
+ case ENOMEM:
+ /* mincore() doesn't always agree with msync() on Linux, so make
+ sure that msync() also thinks addr is not mapped. */
+ if (msync ((void *) addr, len, MS_ASYNC) != -1)
+ goto MINCORE_OUT;
+ return -1;
+ case EFAULT: case EINVAL: default: abort ();
+ }
+ }
+MINCORE_OUT:
#else
- if (msync ((void *) addr, sizeof (unw_word_t), MS_ASYNC) == -1)
-#endif
+ if (msync ((void *) addr, len, MS_ASYNC) == -1)
return -1;
+#endif
victim = lga_victim;
for (i = 0; i < NLGA; i++) {
--
1.6.6
_______________________________________________
Libunwind-devel mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/libunwind-devel