X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fvma-iter.c;h=7673388ae4e5b8b269b248b7c75948ac2b572a3b;hb=1276a2c5f24c0c932426aca9c899fa524d2443f2;hp=46c021297a51b7de172bb3a0d525b9e59b747341;hpb=760b589b90bd4187454960949ed3eb0036512a1e;p=gnulib.git diff --git a/lib/vma-iter.c b/lib/vma-iter.c index 46c021297..7673388ae 100644 --- a/lib/vma-iter.c +++ b/lib/vma-iter.c @@ -1,5 +1,5 @@ /* Iteration over virtual memory areas. - Copyright (C) 2011 Free Software Foundation, Inc. + Copyright (C) 2011-2014 Free Software Foundation, Inc. Written by Bruno Haible , 2011. This program is free software: you can redistribute it and/or modify @@ -32,7 +32,7 @@ # include /* PIOC*, prmap_t */ #endif -#if defined __APPLE__ && defined __MACH__ /* MacOS X */ +#if defined __APPLE__ && defined __MACH__ /* Mac OS X */ # include #endif @@ -44,6 +44,11 @@ # include #endif +#if HAVE_MQUERY /* OpenBSD */ +# include +# include /* mquery */ +#endif + /* Support for reading text files in the /proc file system. */ @@ -354,7 +359,7 @@ vma_iterate (vma_iterate_callback_fn callback, void *data) close (fd); return; -#elif defined __APPLE__ && defined __MACH__ /* MacOS X */ +#elif defined __APPLE__ && defined __MACH__ /* Mac OS X */ task_t task = mach_task_self (); vm_address_t address; @@ -365,10 +370,10 @@ vma_iterate (vma_iterate_callback_fn callback, void *data) int more; mach_port_t object_name; unsigned int flags; - /* In MacOS X 10.5, the types vm_address_t, vm_offset_t, vm_size_t have + /* In Mac OS X 10.5, the types vm_address_t, vm_offset_t, vm_size_t have 32 bits in 32-bit processes and 64 bits in 64-bit processes. Whereas mach_vm_address_t and mach_vm_size_t are always 64 bits large. - MacOS X 10.5 has three vm_region like methods: + Mac OS X 10.5 has three vm_region like methods: - vm_region. It has arguments that depend on whether the current process is 32-bit or 64-bit. When linking dynamically, this function exists only in 32-bit processes. Therefore we use it only @@ -490,6 +495,99 @@ vma_iterate (vma_iterate_callback_fn callback, void *data) break; } +#elif HAVE_MQUERY /* OpenBSD */ + + uintptr_t pagesize; + uintptr_t address; + int /*bool*/ address_known_mapped; + + pagesize = getpagesize (); + /* Avoid calling mquery with a NULL first argument, because this argument + value has a specific meaning. We know the NULL page is unmapped. */ + address = pagesize; + address_known_mapped = 0; + for (;;) + { + /* Test whether the page at address is mapped. */ + if (address_known_mapped + || mquery ((void *) address, pagesize, 0, MAP_FIXED, -1, 0) + == (void *) -1) + { + /* The page at address is mapped. + This is the start of an interval. */ + uintptr_t start = address; + uintptr_t end; + + /* Find the end of the interval. */ + end = (uintptr_t) mquery ((void *) address, pagesize, 0, 0, -1, 0); + if (end == (uintptr_t) (void *) -1) + end = 0; /* wrap around */ + address = end; + + /* It's too complicated to find out about the flags. Just pass 0. */ + if (callback (data, start, end, 0)) + break; + + if (address < pagesize) /* wrap around? */ + break; + } + /* Here we know that the page at address is unmapped. */ + { + uintptr_t query_size = pagesize; + + address += pagesize; + + /* Query larger and larger blocks, to get through the unmapped address + range with few mquery() calls. */ + for (;;) + { + if (2 * query_size > query_size) + query_size = 2 * query_size; + if (address + query_size - 1 < query_size) /* wrap around? */ + { + address_known_mapped = 0; + break; + } + if (mquery ((void *) address, query_size, 0, MAP_FIXED, -1, 0) + == (void *) -1) + { + /* Not all the interval [address .. address + query_size - 1] + is unmapped. */ + address_known_mapped = (query_size == pagesize); + break; + } + /* The interval [address .. address + query_size - 1] is + unmapped. */ + address += query_size; + } + /* Reduce the query size again, to determine the precise size of the + unmapped interval that starts at address. */ + while (query_size > pagesize) + { + query_size = query_size / 2; + if (address + query_size - 1 >= query_size) + { + if (mquery ((void *) address, query_size, 0, MAP_FIXED, -1, 0) + != (void *) -1) + { + /* The interval [address .. address + query_size - 1] is + unmapped. */ + address += query_size; + address_known_mapped = 0; + } + else + address_known_mapped = (query_size == pagesize); + } + } + /* Here again query_size = pagesize, and + either address + pagesize - 1 < pagesize, or + mquery ((void *) address, pagesize, 0, MAP_FIXED, -1, 0) fails. + So, the unmapped area ends at address. */ + } + if (address + pagesize - 1 < pagesize) /* wrap around? */ + break; + } + #endif }