strerror_r-posix: Fixes for MSVC 14.
[gnulib.git] / lib / vma-iter.c
blobe81b8ea1ceef0b697a062005bd21b2bdf32c9821
1 /* Iteration over virtual memory areas.
2 Copyright (C) 2011-2017 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2011.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 #include <config.h>
20 /* Specification. */
21 #include "vma-iter.h"
23 #include <errno.h> /* errno */
24 #include <stdlib.h> /* size_t */
25 #include <fcntl.h> /* open, O_RDONLY */
26 #include <unistd.h> /* getpagesize, read, close, getpid */
28 #if defined __sgi || defined __osf__ /* IRIX, OSF/1 */
29 # include <string.h> /* memcpy */
30 # include <sys/types.h>
31 # include <sys/mman.h> /* mmap, munmap */
32 # include <sys/procfs.h> /* PIOC*, prmap_t */
33 #endif
35 #if defined __sun && HAVE_SYS_PROCFS_H /* Solaris */
36 # include <string.h> /* memcpy */
37 # include <sys/types.h>
38 # include <sys/mman.h> /* mmap, munmap */
39 /* Try to use the newer ("structured") /proc filesystem API, if supported. */
40 # define _STRUCTURED_PROC 1
41 # include <sys/procfs.h> /* prmap_t, optionally PIOC* */
42 #endif
44 #if HAVE_PSTAT_GETPROCVM /* HP-UX */
45 # include <sys/pstat.h> /* pstat_getprocvm */
46 #endif
48 #if defined __APPLE__ && defined __MACH__ /* Mac OS X */
49 # include <mach/mach.h>
50 #endif
52 #if (defined _WIN32 || defined __WIN32__) || defined __CYGWIN__ /* Windows */
53 # include <windows.h>
54 #endif
56 #if defined __BEOS__ || defined __HAIKU__ /* BeOS, Haiku */
57 # include <OS.h>
58 #endif
60 #if HAVE_MQUERY /* OpenBSD */
61 # include <sys/types.h>
62 # include <sys/mman.h> /* mquery */
63 #endif
65 /* Note: On AIX, there is a /proc/$pic/map file, that contains records of type
66 prmap_t, defined in <sys/procfs.h>. But it lists only the virtual memory
67 areas that are connected to a file, not the anonymous ones. */
70 /* Support for reading text files in the /proc file system. */
72 #if defined __linux__ || defined __FreeBSD__ || defined __NetBSD__ /* || defined __CYGWIN__ */
74 /* Buffered read-only streams.
75 We cannot use <stdio.h> here, because fopen() calls malloc(), and a malloc()
76 call may call mmap() and thus pre-allocate available memory. */
78 struct rofile
80 int fd;
81 size_t position;
82 size_t filled;
83 int eof_seen;
84 char buffer[1024];
87 /* Open a read-only file stream. */
88 static int
89 rof_open (struct rofile *rof, const char *filename)
91 int fd = open (filename, O_RDONLY);
92 if (fd < 0)
93 return -1;
94 rof->fd = fd;
95 rof->position = 0;
96 rof->filled = 0;
97 rof->eof_seen = 0;
98 return 0;
101 /* Return the next byte from a read-only file stream without consuming it,
102 or -1 at EOF. */
103 static int
104 rof_peekchar (struct rofile *rof)
106 if (rof->position == rof->filled)
108 if (rof->eof_seen)
109 return -1;
110 else
111 for (;;)
113 int n = read (rof->fd, rof->buffer, sizeof (rof->buffer));
114 # ifdef EINTR
115 if (n < 0 && errno == EINTR)
116 continue;
117 # endif
118 if (n <= 0)
120 rof->eof_seen = 1;
121 return -1;
123 rof->filled = n;
124 rof->position = 0;
125 break;
128 return (unsigned char) rof->buffer[rof->position];
131 /* Return the next byte from a read-only file stream, or -1 at EOF. */
132 static int
133 rof_getchar (struct rofile *rof)
135 int c = rof_peekchar (rof);
136 if (c >= 0)
137 rof->position++;
138 return c;
141 /* Parse an unsigned hexadecimal number from a read-only file stream. */
142 static int
143 rof_scanf_lx (struct rofile *rof, unsigned long *valuep)
145 unsigned long value = 0;
146 unsigned int numdigits = 0;
147 for (;;)
149 int c = rof_peekchar (rof);
150 if (c >= '0' && c <= '9')
151 value = (value << 4) + (c - '0');
152 else if (c >= 'A' && c <= 'F')
153 value = (value << 4) + (c - 'A' + 10);
154 else if (c >= 'a' && c <= 'f')
155 value = (value << 4) + (c - 'a' + 10);
156 else
157 break;
158 rof_getchar (rof);
159 numdigits++;
161 if (numdigits == 0)
162 return -1;
163 *valuep = value;
164 return 0;
167 /* Close a read-only file stream. */
168 static void
169 rof_close (struct rofile *rof)
171 close (rof->fd);
174 #endif
178 vma_iterate (vma_iterate_callback_fn callback, void *data)
180 #if defined __linux__ /* || defined __CYGWIN__ */
182 struct rofile rof;
183 int c;
185 /* Open the current process' maps file. It describes one VMA per line. */
186 if (rof_open (&rof, "/proc/self/maps") < 0)
187 return -1;
189 for (;;)
191 unsigned long start, end;
192 unsigned int flags;
194 /* Parse one line. First start and end. */
195 if (!(rof_scanf_lx (&rof, &start) >= 0
196 && rof_getchar (&rof) == '-'
197 && rof_scanf_lx (&rof, &end) >= 0))
198 break;
199 /* Then the flags. */
201 c = rof_getchar (&rof);
202 while (c == ' ');
203 flags = 0;
204 if (c == 'r')
205 flags |= VMA_PROT_READ;
206 c = rof_getchar (&rof);
207 if (c == 'w')
208 flags |= VMA_PROT_WRITE;
209 c = rof_getchar (&rof);
210 if (c == 'x')
211 flags |= VMA_PROT_EXECUTE;
212 while (c = rof_getchar (&rof), c != -1 && c != '\n')
215 if (callback (data, start, end, flags))
216 break;
218 rof_close (&rof);
219 return 0;
221 #elif defined __FreeBSD__ || defined __NetBSD__
223 struct rofile rof;
224 int c;
226 /* Open the current process' maps file. It describes one VMA per line. */
227 if (rof_open (&rof, "/proc/curproc/map") < 0)
228 return -1;
230 for (;;)
232 unsigned long start, end;
233 unsigned int flags;
235 /* Parse one line. First start. */
236 if (!(rof_getchar (&rof) == '0'
237 && rof_getchar (&rof) == 'x'
238 && rof_scanf_lx (&rof, &start) >= 0))
239 break;
240 while (c = rof_peekchar (&rof), c == ' ' || c == '\t')
241 rof_getchar (&rof);
242 /* Then end. */
243 if (!(rof_getchar (&rof) == '0'
244 && rof_getchar (&rof) == 'x'
245 && rof_scanf_lx (&rof, &end) >= 0))
246 break;
247 /* Then the flags. */
249 c = rof_getchar (&rof);
250 while (c == ' ');
251 flags = 0;
252 if (c == 'r')
253 flags |= VMA_PROT_READ;
254 c = rof_getchar (&rof);
255 if (c == 'w')
256 flags |= VMA_PROT_WRITE;
257 c = rof_getchar (&rof);
258 if (c == 'x')
259 flags |= VMA_PROT_EXECUTE;
260 while (c = rof_getchar (&rof), c != -1 && c != '\n')
263 if (callback (data, start, end, flags))
264 break;
266 rof_close (&rof);
267 return 0;
269 #elif defined __sgi || defined __osf__ /* IRIX, OSF/1 */
271 size_t pagesize;
272 char fnamebuf[6+10+1];
273 char *fname;
274 int fd;
275 int nmaps;
276 size_t memneed;
277 # if HAVE_MAP_ANONYMOUS
278 # define zero_fd -1
279 # define map_flags MAP_ANONYMOUS
280 # else
281 int zero_fd;
282 # define map_flags 0
283 # endif
284 void *auxmap;
285 unsigned long auxmap_start;
286 unsigned long auxmap_end;
287 prmap_t* maps;
288 prmap_t* mp;
290 pagesize = getpagesize ();
292 /* Construct fname = sprintf (fnamebuf+i, "/proc/%u", getpid ()). */
293 fname = fnamebuf + sizeof (fnamebuf) - 1;
294 *fname = '\0';
296 unsigned int value = getpid ();
298 *--fname = (value % 10) + '0';
299 while ((value = value / 10) > 0);
301 fname -= 6;
302 memcpy (fname, "/proc/", 6);
304 fd = open (fname, O_RDONLY);
305 if (fd < 0)
306 return -1;
308 if (ioctl (fd, PIOCNMAP, &nmaps) < 0)
309 goto fail2;
311 memneed = (nmaps + 10) * sizeof (prmap_t);
312 /* Allocate memneed bytes of memory.
313 We cannot use alloca here, because not much stack space is guaranteed.
314 We also cannot use malloc here, because a malloc() call may call mmap()
315 and thus pre-allocate available memory.
316 So use mmap(), and ignore the resulting VMA. */
317 memneed = ((memneed - 1) / pagesize + 1) * pagesize;
318 # if !HAVE_MAP_ANONYMOUS
319 zero_fd = open ("/dev/zero", O_RDONLY, 0644);
320 if (zero_fd < 0)
321 goto fail2;
322 # endif
323 auxmap = (void *) mmap ((void *) 0, memneed, PROT_READ | PROT_WRITE,
324 map_flags | MAP_PRIVATE, zero_fd, 0);
325 # if !HAVE_MAP_ANONYMOUS
326 close (zero_fd);
327 # endif
328 if (auxmap == (void *) -1)
329 goto fail2;
330 auxmap_start = (unsigned long) auxmap;
331 auxmap_end = auxmap_start + memneed;
332 maps = (prmap_t *) auxmap;
334 if (ioctl (fd, PIOCMAP, maps) < 0)
335 goto fail1;
337 for (mp = maps;;)
339 unsigned long start, end;
340 unsigned int flags;
342 start = (unsigned long) mp->pr_vaddr;
343 end = start + mp->pr_size;
344 if (start == 0 && end == 0)
345 break;
346 flags = 0;
347 if (mp->pr_mflags & MA_READ)
348 flags |= VMA_PROT_READ;
349 if (mp->pr_mflags & MA_WRITE)
350 flags |= VMA_PROT_WRITE;
351 if (mp->pr_mflags & MA_EXEC)
352 flags |= VMA_PROT_EXECUTE;
353 mp++;
354 if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
356 /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
357 = [start,auxmap_start-1] u [auxmap_end,end-1]. */
358 if (start < auxmap_start)
359 if (callback (data, start, auxmap_start, flags))
360 break;
361 if (auxmap_end - 1 < end - 1)
362 if (callback (data, auxmap_end, end, flags))
363 break;
365 else
367 if (callback (data, start, end, flags))
368 break;
371 munmap (auxmap, memneed);
372 close (fd);
373 return 0;
375 fail1:
376 munmap (auxmap, memneed);
377 fail2:
378 close (fd);
379 return -1;
381 #elif defined __sun && HAVE_SYS_PROCFS_H /* Solaris */
383 /* Note: Solaris <sys/procfs.h> defines a different type prmap_t with
384 _STRUCTURED_PROC than without! Here's a table of sizeof(prmap_t):
385 32-bit 64-bit
386 _STRUCTURED_PROC = 0 32 56
387 _STRUCTURED_PROC = 1 96 104
388 Therefore, if the include files provide the newer API, prmap_t has
389 the bigger size, and thus you MUST use the newer API. And if the
390 include files provide the older API, prmap_t has the smaller size,
391 and thus you MUST use the older API. */
393 # if defined PIOCNMAP && defined PIOCMAP
394 /* We must use the older /proc interface. */
396 size_t pagesize;
397 char fnamebuf[6+10+1];
398 char *fname;
399 int fd;
400 int nmaps;
401 size_t memneed;
402 # if HAVE_MAP_ANONYMOUS
403 # define zero_fd -1
404 # define map_flags MAP_ANONYMOUS
405 # else /* Solaris <= 7 */
406 int zero_fd;
407 # define map_flags 0
408 # endif
409 void *auxmap;
410 unsigned long auxmap_start;
411 unsigned long auxmap_end;
412 prmap_t* maps;
413 prmap_t* mp;
415 pagesize = getpagesize ();
417 /* Construct fname = sprintf (fnamebuf+i, "/proc/%u", getpid ()). */
418 fname = fnamebuf + sizeof (fnamebuf) - 1;
419 *fname = '\0';
421 unsigned int value = getpid ();
423 *--fname = (value % 10) + '0';
424 while ((value = value / 10) > 0);
426 fname -= 6;
427 memcpy (fname, "/proc/", 6);
429 fd = open (fname, O_RDONLY);
430 if (fd < 0)
431 return -1;
433 if (ioctl (fd, PIOCNMAP, &nmaps) < 0)
434 goto fail2;
436 memneed = (nmaps + 10) * sizeof (prmap_t);
437 /* Allocate memneed bytes of memory.
438 We cannot use alloca here, because not much stack space is guaranteed.
439 We also cannot use malloc here, because a malloc() call may call mmap()
440 and thus pre-allocate available memory.
441 So use mmap(), and ignore the resulting VMA. */
442 memneed = ((memneed - 1) / pagesize + 1) * pagesize;
443 # if !HAVE_MAP_ANONYMOUS
444 zero_fd = open ("/dev/zero", O_RDONLY, 0644);
445 if (zero_fd < 0)
446 goto fail2;
447 # endif
448 auxmap = (void *) mmap ((void *) 0, memneed, PROT_READ | PROT_WRITE,
449 map_flags | MAP_PRIVATE, zero_fd, 0);
450 # if !HAVE_MAP_ANONYMOUS
451 close (zero_fd);
452 # endif
453 if (auxmap == (void *) -1)
454 goto fail2;
455 auxmap_start = (unsigned long) auxmap;
456 auxmap_end = auxmap_start + memneed;
457 maps = (prmap_t *) auxmap;
459 if (ioctl (fd, PIOCMAP, maps) < 0)
460 goto fail1;
462 for (mp = maps;;)
464 unsigned long start, end;
465 unsigned int flags;
467 start = (unsigned long) mp->pr_vaddr;
468 end = start + mp->pr_size;
469 if (start == 0 && end == 0)
470 break;
471 flags = 0;
472 if (mp->pr_mflags & MA_READ)
473 flags |= VMA_PROT_READ;
474 if (mp->pr_mflags & MA_WRITE)
475 flags |= VMA_PROT_WRITE;
476 if (mp->pr_mflags & MA_EXEC)
477 flags |= VMA_PROT_EXECUTE;
478 mp++;
479 if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
481 /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
482 = [start,auxmap_start-1] u [auxmap_end,end-1]. */
483 if (start < auxmap_start)
484 if (callback (data, start, auxmap_start, flags))
485 break;
486 if (auxmap_end - 1 < end - 1)
487 if (callback (data, auxmap_end, end, flags))
488 break;
490 else
492 if (callback (data, start, end, flags))
493 break;
496 munmap (auxmap, memneed);
497 close (fd);
498 return 0;
500 fail1:
501 munmap (auxmap, memneed);
502 fail2:
503 close (fd);
504 return -1;
506 # else
507 /* We must use the newer /proc interface.
508 Documentation:
509 https://docs.oracle.com/cd/E23824_01/html/821-1473/proc-4.html
510 The contents of /proc/<pid>/map consists of records of type
511 prmap_t. These are different in 32-bit and 64-bit processes,
512 but here we are fortunately accessing only the current process. */
514 size_t pagesize;
515 char fnamebuf[6+10+4+1];
516 char *fname;
517 int fd;
518 int nmaps;
519 size_t memneed;
520 # if HAVE_MAP_ANONYMOUS
521 # define zero_fd -1
522 # define map_flags MAP_ANONYMOUS
523 # else /* Solaris <= 7 */
524 int zero_fd;
525 # define map_flags 0
526 # endif
527 void *auxmap;
528 unsigned long auxmap_start;
529 unsigned long auxmap_end;
530 prmap_t* maps;
531 prmap_t* maps_end;
532 prmap_t* mp;
534 pagesize = getpagesize ();
536 /* Construct fname = sprintf (fnamebuf+i, "/proc/%u/map", getpid ()). */
537 fname = fnamebuf + sizeof (fnamebuf) - 1 - 4;
538 memcpy (fname, "/map", 4 + 1);
540 unsigned int value = getpid ();
542 *--fname = (value % 10) + '0';
543 while ((value = value / 10) > 0);
545 fname -= 6;
546 memcpy (fname, "/proc/", 6);
548 fd = open (fname, O_RDONLY);
549 if (fd < 0)
550 return -1;
553 struct stat statbuf;
554 if (fstat (fd, &statbuf) < 0)
555 goto fail2;
556 nmaps = statbuf.st_size / sizeof (prmap_t);
559 memneed = (nmaps + 10) * sizeof (prmap_t);
560 /* Allocate memneed bytes of memory.
561 We cannot use alloca here, because not much stack space is guaranteed.
562 We also cannot use malloc here, because a malloc() call may call mmap()
563 and thus pre-allocate available memory.
564 So use mmap(), and ignore the resulting VMA. */
565 memneed = ((memneed - 1) / pagesize + 1) * pagesize;
566 # if !HAVE_MAP_ANONYMOUS
567 zero_fd = open ("/dev/zero", O_RDONLY, 0644);
568 if (zero_fd < 0)
569 goto fail2;
570 # endif
571 auxmap = (void *) mmap ((void *) 0, memneed, PROT_READ | PROT_WRITE,
572 map_flags | MAP_PRIVATE, zero_fd, 0);
573 # if !HAVE_MAP_ANONYMOUS
574 close (zero_fd);
575 # endif
576 if (auxmap == (void *) -1)
577 goto fail2;
578 auxmap_start = (unsigned long) auxmap;
579 auxmap_end = auxmap_start + memneed;
580 maps = (prmap_t *) auxmap;
582 /* Read up to memneed bytes from fd into maps. */
584 size_t remaining = memneed;
585 size_t total_read = 0;
586 char *ptr = (char *) maps;
590 size_t nread = read (fd, ptr, remaining);
591 if (nread == (size_t)-1)
593 if (errno == EINTR)
594 continue;
595 goto fail1;
597 if (nread == 0)
598 /* EOF */
599 break;
600 total_read += nread;
601 ptr += nread;
602 remaining -= nread;
604 while (remaining > 0);
606 nmaps = (memneed - remaining) / sizeof (prmap_t);
607 maps_end = maps + nmaps;
610 for (mp = maps; mp < maps_end; mp++)
612 unsigned long start, end;
613 unsigned int flags;
615 start = (unsigned long) mp->pr_vaddr;
616 end = start + mp->pr_size;
617 flags = 0;
618 if (mp->pr_mflags & MA_READ)
619 flags |= VMA_PROT_READ;
620 if (mp->pr_mflags & MA_WRITE)
621 flags |= VMA_PROT_WRITE;
622 if (mp->pr_mflags & MA_EXEC)
623 flags |= VMA_PROT_EXECUTE;
624 if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
626 /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
627 = [start,auxmap_start-1] u [auxmap_end,end-1]. */
628 if (start < auxmap_start)
629 if (callback (data, start, auxmap_start, flags))
630 break;
631 if (auxmap_end - 1 < end - 1)
632 if (callback (data, auxmap_end, end, flags))
633 break;
635 else
637 if (callback (data, start, end, flags))
638 break;
641 munmap (auxmap, memneed);
642 close (fd);
643 return 0;
645 fail1:
646 munmap (auxmap, memneed);
647 fail2:
648 close (fd);
649 return -1;
651 # endif
653 #elif HAVE_PSTAT_GETPROCVM /* HP-UX */
655 unsigned long pagesize = getpagesize ();
656 int i;
658 for (i = 0; ; i++)
660 struct pst_vm_status info;
661 int ret = pstat_getprocvm (&info, sizeof (info), 0, i);
662 if (ret < 0)
663 return -1;
664 if (ret == 0)
665 break;
667 unsigned long start = info.pst_vaddr;
668 unsigned long end = start + info.pst_length * pagesize;
669 unsigned int flags = 0;
670 if (info.pst_permission & PS_PROT_READ)
671 flags |= VMA_PROT_READ;
672 if (info.pst_permission & PS_PROT_WRITE)
673 flags |= VMA_PROT_WRITE;
674 if (info.pst_permission & PS_PROT_EXECUTE)
675 flags |= VMA_PROT_EXECUTE;
677 if (callback (data, start, end, flags))
678 break;
682 #elif defined __APPLE__ && defined __MACH__ /* Mac OS X */
684 task_t task = mach_task_self ();
685 vm_address_t address;
686 vm_size_t size;
688 for (address = VM_MIN_ADDRESS;; address += size)
690 int more;
691 mach_port_t object_name;
692 unsigned int flags;
693 /* In Mac OS X 10.5, the types vm_address_t, vm_offset_t, vm_size_t have
694 32 bits in 32-bit processes and 64 bits in 64-bit processes. Whereas
695 mach_vm_address_t and mach_vm_size_t are always 64 bits large.
696 Mac OS X 10.5 has three vm_region like methods:
697 - vm_region. It has arguments that depend on whether the current
698 process is 32-bit or 64-bit. When linking dynamically, this
699 function exists only in 32-bit processes. Therefore we use it only
700 in 32-bit processes.
701 - vm_region_64. It has arguments that depend on whether the current
702 process is 32-bit or 64-bit. It interprets a flavor
703 VM_REGION_BASIC_INFO as VM_REGION_BASIC_INFO_64, which is
704 dangerous since 'struct vm_region_basic_info_64' is larger than
705 'struct vm_region_basic_info'; therefore let's write
706 VM_REGION_BASIC_INFO_64 explicitly.
707 - mach_vm_region. It has arguments that are 64-bit always. This
708 function is useful when you want to access the VM of a process
709 other than the current process.
710 In 64-bit processes, we could use vm_region_64 or mach_vm_region.
711 I choose vm_region_64 because it uses the same types as vm_region,
712 resulting in less conditional code. */
713 # if defined __ppc64__ || defined __x86_64__
714 struct vm_region_basic_info_64 info;
715 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
717 more = (vm_region_64 (task, &address, &size, VM_REGION_BASIC_INFO_64,
718 (vm_region_info_t)&info, &info_count, &object_name)
719 == KERN_SUCCESS);
720 # else
721 struct vm_region_basic_info info;
722 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
724 more = (vm_region (task, &address, &size, VM_REGION_BASIC_INFO,
725 (vm_region_info_t)&info, &info_count, &object_name)
726 == KERN_SUCCESS);
727 # endif
728 if (object_name != MACH_PORT_NULL)
729 mach_port_deallocate (mach_task_self (), object_name);
730 if (!more)
731 break;
732 flags = 0;
733 if (info.protection & VM_PROT_READ)
734 flags |= VMA_PROT_READ;
735 if (info.protection & VM_PROT_WRITE)
736 flags |= VMA_PROT_WRITE;
737 if (info.protection & VM_PROT_EXECUTE)
738 flags |= VMA_PROT_EXECUTE;
739 if (callback (data, address, address + size, flags))
740 break;
742 return 0;
744 #elif (defined _WIN32 || defined __WIN32__) || defined __CYGWIN__
745 /* Windows platform. Use the native Windows API. */
747 MEMORY_BASIC_INFORMATION info;
748 uintptr_t address = 0;
750 while (VirtualQuery ((void*)address, &info, sizeof(info)) == sizeof(info))
752 if (info.State != MEM_FREE)
753 /* Ignore areas where info.State has the value MEM_RESERVE or,
754 equivalently, info.Protect has the undocumented value 0.
755 This is needed, so that on Cygwin, areas used by malloc() are
756 distinguished from areas reserved for future malloc(). */
757 if (info.State != MEM_RESERVE)
759 uintptr_t start, end;
760 unsigned int flags;
762 start = (uintptr_t)info.BaseAddress;
763 end = start + info.RegionSize;
764 switch (info.Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
766 case PAGE_READONLY:
767 flags = VMA_PROT_READ;
768 break;
769 case PAGE_READWRITE:
770 case PAGE_WRITECOPY:
771 flags = VMA_PROT_READ | VMA_PROT_WRITE;
772 break;
773 case PAGE_EXECUTE:
774 flags = VMA_PROT_EXECUTE;
775 break;
776 case PAGE_EXECUTE_READ:
777 flags = VMA_PROT_READ | VMA_PROT_EXECUTE;
778 break;
779 case PAGE_EXECUTE_READWRITE:
780 case PAGE_EXECUTE_WRITECOPY:
781 flags = VMA_PROT_READ | VMA_PROT_WRITE | VMA_PROT_EXECUTE;
782 break;
783 case PAGE_NOACCESS:
784 default:
785 flags = 0;
786 break;
789 if (callback (data, start, end, flags))
790 break;
792 address = (uintptr_t)info.BaseAddress + info.RegionSize;
794 return 0;
796 #elif defined __BEOS__ || defined __HAIKU__
797 /* Use the BeOS specific API. */
799 area_info info;
800 int32 cookie;
802 cookie = 0;
803 while (get_next_area_info (0, &cookie, &info) == B_OK)
805 unsigned long start, end;
806 unsigned int flags;
808 start = (unsigned long) info.address;
809 end = start + info.size;
810 flags = 0;
811 if (info.protection & B_READ_AREA)
812 flags |= VMA_PROT_READ | VMA_PROT_EXECUTE;
813 if (info.protection & B_WRITE_AREA)
814 flags |= VMA_PROT_WRITE;
816 if (callback (data, start, end, flags))
817 break;
819 return 0;
821 #elif HAVE_MQUERY /* OpenBSD */
823 uintptr_t pagesize;
824 uintptr_t address;
825 int /*bool*/ address_known_mapped;
827 pagesize = getpagesize ();
828 /* Avoid calling mquery with a NULL first argument, because this argument
829 value has a specific meaning. We know the NULL page is unmapped. */
830 address = pagesize;
831 address_known_mapped = 0;
832 for (;;)
834 /* Test whether the page at address is mapped. */
835 if (address_known_mapped
836 || mquery ((void *) address, pagesize, 0, MAP_FIXED, -1, 0)
837 == (void *) -1)
839 /* The page at address is mapped.
840 This is the start of an interval. */
841 uintptr_t start = address;
842 uintptr_t end;
844 /* Find the end of the interval. */
845 end = (uintptr_t) mquery ((void *) address, pagesize, 0, 0, -1, 0);
846 if (end == (uintptr_t) (void *) -1)
847 end = 0; /* wrap around */
848 address = end;
850 /* It's too complicated to find out about the flags. Just pass 0. */
851 if (callback (data, start, end, 0))
852 break;
854 if (address < pagesize) /* wrap around? */
855 break;
857 /* Here we know that the page at address is unmapped. */
859 uintptr_t query_size = pagesize;
861 address += pagesize;
863 /* Query larger and larger blocks, to get through the unmapped address
864 range with few mquery() calls. */
865 for (;;)
867 if (2 * query_size > query_size)
868 query_size = 2 * query_size;
869 if (address + query_size - 1 < query_size) /* wrap around? */
871 address_known_mapped = 0;
872 break;
874 if (mquery ((void *) address, query_size, 0, MAP_FIXED, -1, 0)
875 == (void *) -1)
877 /* Not all the interval [address .. address + query_size - 1]
878 is unmapped. */
879 address_known_mapped = (query_size == pagesize);
880 break;
882 /* The interval [address .. address + query_size - 1] is
883 unmapped. */
884 address += query_size;
886 /* Reduce the query size again, to determine the precise size of the
887 unmapped interval that starts at address. */
888 while (query_size > pagesize)
890 query_size = query_size / 2;
891 if (address + query_size - 1 >= query_size)
893 if (mquery ((void *) address, query_size, 0, MAP_FIXED, -1, 0)
894 != (void *) -1)
896 /* The interval [address .. address + query_size - 1] is
897 unmapped. */
898 address += query_size;
899 address_known_mapped = 0;
901 else
902 address_known_mapped = (query_size == pagesize);
905 /* Here again query_size = pagesize, and
906 either address + pagesize - 1 < pagesize, or
907 mquery ((void *) address, pagesize, 0, MAP_FIXED, -1, 0) fails.
908 So, the unmapped area ends at address. */
910 if (address + pagesize - 1 < pagesize) /* wrap around? */
911 break;
913 return 0;
915 #else
917 /* Not implemented. */
918 return -1;
920 #endif
924 #ifdef TEST
926 #include <stdio.h>
928 /* Output the VMAs of the current process in a format similar to the Linux
929 /proc/$pid/maps file. */
931 static int
932 vma_iterate_callback (void *data, uintptr_t start, uintptr_t end,
933 unsigned int flags)
935 printf ("%08lx-%08lx %c%c%c\n",
936 (unsigned long) start, (unsigned long) end,
937 flags & VMA_PROT_READ ? 'r' : '-',
938 flags & VMA_PROT_WRITE ? 'w' : '-',
939 flags & VMA_PROT_EXECUTE ? 'x' : '-');
940 return 0;
944 main ()
946 vma_iterate (vma_iterate_callback, NULL);
948 /* Let the user interactively look at the /proc file system. */
949 sleep (10);
951 return 0;
954 #endif /* TEST */