X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fvma-iter.c;h=1de69d803ebd90f1718beb22a70d63ac21e3ae18;hb=50901279d8e42ea4bccc2eef0a6b11e7c3dde4cf;hp=8ef865de7ffd237cd5b12baed5493fd841cdfa31;hpb=5e5009f839875220d5dec7abdf5cf53d919f4d42;p=gnulib.git diff --git a/lib/vma-iter.c b/lib/vma-iter.c index 8ef865de7..1de69d803 100644 --- a/lib/vma-iter.c +++ b/lib/vma-iter.c @@ -40,10 +40,15 @@ # include #endif -#if defined __BEOS__ /* BeOS */ +#if defined __BEOS__ || defined __HAIKU__ /* BeOS, Haiku */ # include #endif +#if HAVE_MQUERY /* OpenBSD */ +# include +# include /* mquery */ +#endif + /* Support for reading text files in the /proc file system. */ @@ -466,7 +471,7 @@ vma_iterate (vma_iterate_callback_fn callback, void *data) address = (unsigned long)info.BaseAddress + info.RegionSize; } -#elif defined __BEOS__ +#elif defined __BEOS__ || defined __HAIKU__ /* Use the BeOS specific API. */ area_info info; @@ -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 }