diff options
Diffstat (limited to 'libsigsegv/src/stackvma-mincore.c')
-rw-r--r-- | libsigsegv/src/stackvma-mincore.c | 275 |
1 files changed, 0 insertions, 275 deletions
diff --git a/libsigsegv/src/stackvma-mincore.c b/libsigsegv/src/stackvma-mincore.c deleted file mode 100644 index 1b51ef23..00000000 --- a/libsigsegv/src/stackvma-mincore.c +++ /dev/null @@ -1,275 +0,0 @@ -/* Determine the virtual memory area of a given address. - Copyright (C) 2006, 2008 Bruno Haible <bruno@clisp.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - -/* mincore() is a system call that allows to inquire the status of a - range of pages of virtual memory. In particular, it allows to inquire - whether a page is mapped at all. - As of 2006, mincore() is supported by: possible bits: - - Linux, since Linux 2.4 and glibc 2.2, 1 - - Solaris, since Solaris 9, 1 - - MacOS X, since MacOS X 10.3 (at least), 1 - - FreeBSD, since FreeBSD 6.0, MINCORE_{INCORE,REFERENCED,MODIFIED} - - NetBSD, since NetBSD 3.0 (at least), 1 - - OpenBSD, since OpenBSD 2.6 (at least), 1 - However, while the API allows to easily determine the bounds of mapped - virtual memory, it does not make it easy the bounds of _unmapped_ virtual - memory ranges. We try to work around this, but it may still be slow. */ - -#include "stackvma.h" -#include <limits.h> -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif -#include <sys/types.h> -#include <sys/mman.h> - -/* Cache for getpagesize(). */ -static unsigned long pagesize; - -/* Initialize pagesize. */ -static void -init_pagesize (void) -{ -#if HAVE_GETPAGESIZE - pagesize = getpagesize (); -#elif HAVE_SYSCONF_PAGESIZE - pagesize = sysconf (_SC_PAGESIZE); -#else - pagesize = PAGESIZE; -#endif -} - -/* Test whether the page starting at ADDR is among the address range. - ADDR must be a multiple of pagesize. */ -static int -is_mapped (unsigned long addr) -{ - char vec[1]; - return mincore ((void *) addr, pagesize, vec) >= 0; -} - -/* Assuming that the page starting at ADDR is among the address range, - return the start of its virtual memory range. - ADDR must be a multiple of pagesize. */ -static unsigned long -mapped_range_start (unsigned long addr) -{ - /* Use a moderately sized VEC here, small enough that it fits on the stack - (without requiring malloc). */ - char vec[2048]; - unsigned long stepsize = sizeof (vec); - - for (;;) - { - unsigned long max_remaining; - - if (addr == 0) - return addr; - - max_remaining = addr / pagesize; - if (stepsize > max_remaining) - stepsize = max_remaining; - if (mincore ((void *) (addr - stepsize * pagesize), - stepsize * pagesize, vec) < 0) - /* Time to search in smaller steps. */ - break; - /* The entire range exists. Continue searching in large steps. */ - addr -= stepsize * pagesize; - } - for (;;) - { - unsigned long halfstepsize1; - unsigned long halfstepsize2; - - if (stepsize == 1) - return addr; - - /* Here we know that less than stepsize pages exist starting at addr. */ - halfstepsize1 = (stepsize + 1) / 2; - halfstepsize2 = stepsize / 2; - /* halfstepsize1 + halfstepsize2 = stepsize. */ - - if (mincore ((void *) (addr - halfstepsize1 * pagesize), - halfstepsize1 * pagesize, vec) < 0) - stepsize = halfstepsize1; - else - { - addr -= halfstepsize1 * pagesize; - stepsize = halfstepsize2; - } - } -} - -/* Assuming that the page starting at ADDR is among the address range, - return the end of its virtual memory range + 1. - ADDR must be a multiple of pagesize. */ -static unsigned long -mapped_range_end (unsigned long addr) -{ - /* Use a moderately sized VEC here, small enough that it fits on the stack - (without requiring malloc). */ - char vec[2048]; - unsigned long stepsize = sizeof (vec); - - addr += pagesize; - for (;;) - { - unsigned long max_remaining; - - if (addr == 0) /* wrapped around? */ - return addr; - - max_remaining = (- addr) / pagesize; - if (stepsize > max_remaining) - stepsize = max_remaining; - if (mincore ((void *) addr, stepsize * pagesize, vec) < 0) - /* Time to search in smaller steps. */ - break; - /* The entire range exists. Continue searching in large steps. */ - addr += stepsize * pagesize; - } - for (;;) - { - unsigned long halfstepsize1; - unsigned long halfstepsize2; - - if (stepsize == 1) - return addr; - - /* Here we know that less than stepsize pages exist starting at addr. */ - halfstepsize1 = (stepsize + 1) / 2; - halfstepsize2 = stepsize / 2; - /* halfstepsize1 + halfstepsize2 = stepsize. */ - - if (mincore ((void *) addr, halfstepsize1 * pagesize, vec) < 0) - stepsize = halfstepsize1; - else - { - addr += halfstepsize1 * pagesize; - stepsize = halfstepsize2; - } - } -} - -/* Determine whether an address range [ADDR1..ADDR2] is completely unmapped. - ADDR1 must be <= ADDR2. */ -static int -is_unmapped (unsigned long addr1, unsigned long addr2) -{ - unsigned long count; - unsigned long stepsize; - - /* Round addr1 down. */ - addr1 = (addr1 / pagesize) * pagesize; - /* Round addr2 up and turn it into an exclusive bound. */ - addr2 = ((addr2 / pagesize) + 1) * pagesize; - - /* This is slow: mincore() does not provide a way to determine the bounds - of the gaps directly. So we have to use mincore() on individual pages - over and over again. Only after we've verified that all pages are - unmapped, we know that the range is completely unmapped. - If we were to traverse the pages from bottom to top or from top to bottom, - it would be slow even in the average case. To speed up the search, we - exploit the fact that mapped memory ranges are larger than one page on - average, therefore we have good chances of hitting a mapped area if we - traverse only every second, or only fourth page, etc. This doesn't - decrease the worst-case runtime, only the average runtime. */ - count = (addr2 - addr1) / pagesize; - /* We have to test is_mapped (addr1 + i * pagesize) for 0 <= i < count. */ - for (stepsize = 1; stepsize < count; ) - stepsize = 2 * stepsize; - for (;;) - { - unsigned long addr_stepsize; - unsigned long i; - unsigned long addr; - - stepsize = stepsize / 2; - if (stepsize == 0) - break; - addr_stepsize = stepsize * pagesize; - for (i = stepsize, addr = addr1 + addr_stepsize; - i < count; - i += 2 * stepsize, addr += 2 * addr_stepsize) - /* Here addr = addr1 + i * pagesize. */ - if (is_mapped (addr)) - return 0; - } - return 1; -} - -#if STACK_DIRECTION < 0 - -/* Info about the gap between this VMA and the previous one. - addr must be < vma->start. */ -static int -mincore_is_near_this (unsigned long addr, struct vma_struct *vma) -{ - /* vma->start - addr <= (vma->start - vma->prev_end) / 2 - is mathematically equivalent to - vma->prev_end <= 2 * addr - vma->start - <==> is_unmapped (2 * addr - vma->start, vma->start - 1). - But be careful about overflow: if 2 * addr - vma->start is negative, - we consider a tiny "guard page" mapping [0, 0] to be present around - NULL; it intersects the range (2 * addr - vma->start, vma->start - 1), - therefore return false. */ - unsigned long testaddr = addr - (vma->start - addr); - if (testaddr > addr) /* overflow? */ - return 0; - /* Here testaddr <= addr < vma->start. */ - return is_unmapped (testaddr, vma->start - 1); -} - -#endif -#if STACK_DIRECTION > 0 - -/* Info about the gap between this VMA and the next one. - addr must be > vma->end - 1. */ -static int -mincore_is_near_this (unsigned long addr, struct vma_struct *vma) -{ - /* addr - vma->end < (vma->next_start - vma->end) / 2 - is mathematically equivalent to - vma->next_start > 2 * addr - vma->end - <==> is_unmapped (vma->end, 2 * addr - vma->end). - But be careful about overflow: if 2 * addr - vma->end is > ~0UL, - we consider a tiny "guard page" mapping [0, 0] to be present around - NULL; it intersects the range (vma->end, 2 * addr - vma->end), - therefore return false. */ - unsigned long testaddr = addr + (addr - vma->end); - if (testaddr < addr) /* overflow? */ - return 0; - /* Here vma->end - 1 < addr <= testaddr. */ - return is_unmapped (vma->end, testaddr); -} - -#endif - -#ifdef STATIC -STATIC -#endif -int -sigsegv_get_vma (unsigned long address, struct vma_struct *vma) -{ - if (pagesize == 0) - init_pagesize (); - address = (address / pagesize) * pagesize; - vma->start = mapped_range_start (address); - vma->end = mapped_range_end (address); - vma->is_near_this = mincore_is_near_this; - return 0; -} |