root/maint/gnulib/lib/vma-iter.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rof_open
  2. rof_peekchar
  3. rof_getchar
  4. rof_scanf_lx
  5. rof_close
  6. vma_iterate_proc
  7. vma_iterate_proc
  8. vma_iterate_proc
  9. vma_iterate_proc
  10. vma_iterate_bsd
  11. vma_iterate_bsd
  12. vma_iterate_bsd
  13. vma_iterate_bsd
  14. vma_iterate
  15. vma_iterate_callback
  16. main

   1 /* Iteration over virtual memory areas.
   2    Copyright (C) 2011-2021 Free Software Foundation, Inc.
   3    Written by Bruno Haible <bruno@clisp.org>, 2011-2017.
   4 
   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.
   9 
  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.
  14 
  15    You should have received a copy of the GNU General Public License
  16    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  17 
  18 #include <config.h>
  19 
  20 /* On Solaris in 32-bit mode, when gnulib module 'largefile' is in use,
  21    prevent a compilation error
  22      "Cannot use procfs in the large file compilation environment"
  23    On Android, when targeting Android 4.4 or older with a GCC toolchain,
  24    prevent a compilation error
  25      "error: call to 'mmap' declared with attribute error: mmap is not
  26       available with _FILE_OFFSET_BITS=64 when using GCC until android-21.
  27       Either raise your minSdkVersion, disable _FILE_OFFSET_BITS=64, or
  28       switch to Clang."
  29    The files that we access in this compilation unit are less than 2 GB
  30    large.  */
  31 #if defined __sun || defined __ANDROID__
  32 # undef _FILE_OFFSET_BITS
  33 #endif
  34 
  35 /* Specification.  */
  36 #include "vma-iter.h"
  37 
  38 #include <errno.h> /* errno */
  39 #include <stdlib.h> /* size_t */
  40 #include <fcntl.h> /* open, O_RDONLY */
  41 #include <unistd.h> /* getpagesize, lseek, read, close, getpid */
  42 
  43 #if defined __linux__ || defined __ANDROID__
  44 # include <limits.h> /* PATH_MAX */
  45 #endif
  46 
  47 #if defined __linux__ || defined __ANDROID__ || defined __FreeBSD_kernel__ || defined __FreeBSD__ || defined __DragonFly__ || defined __NetBSD__ || defined __minix /* || defined __CYGWIN__ */
  48 # include <sys/types.h>
  49 # include <sys/mman.h> /* mmap, munmap */
  50 #endif
  51 #if defined __minix
  52 # include <string.h> /* memcpy */
  53 #endif
  54 
  55 #if defined __FreeBSD__ || defined __FreeBSD_kernel__ /* FreeBSD, GNU/kFreeBSD */
  56 # include <sys/types.h>
  57 # include <sys/mman.h> /* mmap, munmap */
  58 # include <sys/user.h> /* struct kinfo_vmentry */
  59 # include <sys/sysctl.h> /* sysctl */
  60 #endif
  61 #if defined __NetBSD__ || defined __OpenBSD__ /* NetBSD, OpenBSD */
  62 # include <sys/types.h>
  63 # include <sys/mman.h> /* mmap, munmap */
  64 # include <sys/sysctl.h> /* sysctl, struct kinfo_vmentry */
  65 #endif
  66 
  67 #if defined __sgi || defined __osf__ /* IRIX, OSF/1 */
  68 # include <string.h> /* memcpy */
  69 # include <sys/types.h>
  70 # include <sys/mman.h> /* mmap, munmap */
  71 # include <sys/procfs.h> /* PIOC*, prmap_t */
  72 #endif
  73 
  74 #if defined __sun /* Solaris */
  75 # include <string.h> /* memcpy */
  76 # include <sys/types.h>
  77 # include <sys/mman.h> /* mmap, munmap */
  78 /* Try to use the newer ("structured") /proc filesystem API, if supported.  */
  79 # define _STRUCTURED_PROC 1
  80 # include <sys/procfs.h> /* prmap_t, optionally PIOC* */
  81 #endif
  82 
  83 #if HAVE_PSTAT_GETPROCVM /* HP-UX */
  84 # include <sys/pstat.h> /* pstat_getprocvm */
  85 #endif
  86 
  87 #if defined __APPLE__ && defined __MACH__ /* Mac OS X */
  88 # include <mach/mach.h>
  89 #endif
  90 
  91 #if defined __GNU__ /* GNU/Hurd */
  92 # include <mach/mach.h>
  93 #endif
  94 
  95 #if defined _WIN32 || defined __CYGWIN__ /* Windows */
  96 # include <windows.h>
  97 #endif
  98 
  99 #if defined __BEOS__ || defined __HAIKU__ /* BeOS, Haiku */
 100 # include <OS.h>
 101 #endif
 102 
 103 #if HAVE_MQUERY /* OpenBSD */
 104 # include <sys/types.h>
 105 # include <sys/mman.h> /* mquery */
 106 #endif
 107 
 108 /* Note: On AIX, there is a /proc/$pic/map file, that contains records of type
 109    prmap_t, defined in <sys/procfs.h>.  But it lists only the virtual memory
 110    areas that are connected to a file, not the anonymous ones.  */
 111 
 112 
 113 /* Support for reading text files in the /proc file system.  */
 114 
 115 #if defined __linux__ || defined __ANDROID__ || defined __FreeBSD_kernel__ || defined __FreeBSD__ || defined __DragonFly__ || defined __NetBSD__ || defined __minix /* || defined __CYGWIN__ */
 116 
 117 /* Buffered read-only streams.
 118    We cannot use <stdio.h> here, because fopen() calls malloc(), and a malloc()
 119    call may call mmap() and thus pre-allocate available memory.
 120    Also, we cannot use multiple read() calls, because if the buffer size is
 121    smaller than the file's contents:
 122      - On NetBSD, the second read() call would return 0, thus making the file
 123        appear truncated.
 124      - On DragonFly BSD, the first read() call would fail with errno = EFBIG.
 125      - On all platforms, if some other thread is doing memory allocations or
 126        deallocations between two read() calls, there is a high risk that the
 127        result of these two read() calls don't fit together, and as a
 128        consequence we will parse garbage and either omit some VMAs or return
 129        VMAs with nonsensical addresses.
 130    So use mmap(), and ignore the resulting VMA.  */
 131 
 132 # if defined __linux__ || defined __ANDROID__
 133   /* On Linux, if the file does not entirely fit into the buffer, the read()
 134      function stops before the line that would come out truncated.  The
 135      maximum size of such a line is 73 + PATH_MAX bytes.  To be sure that we
 136      have read everything, we must verify that at least that many bytes are
 137      left when read() returned.  */
 138 #  define MIN_LEFTOVER (73 + PATH_MAX)
 139 # else
 140 #  define MIN_LEFTOVER 1
 141 # endif
 142 
 143 # ifdef TEST
 144 /* During testing, we want to run into the hairy cases.  */
 145 #  define STACK_ALLOCATED_BUFFER_SIZE 32
 146 # else
 147 #  if MIN_LEFTOVER < 1024
 148 #   define STACK_ALLOCATED_BUFFER_SIZE 1024
 149 #  else
 150     /* There is no point in using a stack-allocated buffer if it is too small anyway.  */
 151 #   define STACK_ALLOCATED_BUFFER_SIZE 1
 152 #  endif
 153 # endif
 154 
 155 struct rofile
 156   {
 157     size_t position;
 158     size_t filled;
 159     int eof_seen;
 160     /* These fields deal with allocation of the buffer.  */
 161     char *buffer;
 162     char *auxmap;
 163     size_t auxmap_length;
 164     unsigned long auxmap_start;
 165     unsigned long auxmap_end;
 166     char stack_allocated_buffer[STACK_ALLOCATED_BUFFER_SIZE];
 167   };
 168 
 169 /* Open a read-only file stream.  */
 170 static int
 171 rof_open (struct rofile *rof, const char *filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 172 {
 173   int fd;
 174   unsigned long pagesize;
 175   size_t size;
 176 
 177   fd = open (filename, O_RDONLY | O_CLOEXEC);
 178   if (fd < 0)
 179     return -1;
 180   rof->position = 0;
 181   rof->eof_seen = 0;
 182   /* Try the static buffer first.  */
 183   pagesize = 0;
 184   rof->buffer = rof->stack_allocated_buffer;
 185   size = sizeof (rof->stack_allocated_buffer);
 186   rof->auxmap = NULL;
 187   rof->auxmap_start = 0;
 188   rof->auxmap_end = 0;
 189   for (;;)
 190     {
 191       /* Attempt to read the contents in a single system call.  */
 192       if (size > MIN_LEFTOVER)
 193         {
 194           int n = read (fd, rof->buffer, size);
 195           if (n < 0 && errno == EINTR)
 196             goto retry;
 197 # if defined __DragonFly__
 198           if (!(n < 0 && errno == EFBIG))
 199 # endif
 200             {
 201               if (n <= 0)
 202                 /* Empty file.  */
 203                 goto fail1;
 204               if (n + MIN_LEFTOVER <= size)
 205                 {
 206                   /* The buffer was sufficiently large.  */
 207                   rof->filled = n;
 208 # if defined __linux__ || defined __ANDROID__
 209                   /* On Linux, the read() call may stop even if the buffer was
 210                      large enough.  We need the equivalent of full_read().  */
 211                   for (;;)
 212                     {
 213                       n = read (fd, rof->buffer + rof->filled, size - rof->filled);
 214                       if (n < 0 && errno == EINTR)
 215                         goto retry;
 216                       if (n < 0)
 217                         /* Some error.  */
 218                         goto fail1;
 219                       if (n + MIN_LEFTOVER > size - rof->filled)
 220                         /* Allocate a larger buffer.  */
 221                         break;
 222                       if (n == 0)
 223                         {
 224                           /* Reached the end of file.  */
 225                           close (fd);
 226                           return 0;
 227                         }
 228                       rof->filled += n;
 229                     }
 230 # else
 231                   close (fd);
 232                   return 0;
 233 # endif
 234                 }
 235             }
 236         }
 237       /* Allocate a larger buffer.  */
 238       if (pagesize == 0)
 239         {
 240           pagesize = getpagesize ();
 241           size = pagesize;
 242           while (size <= MIN_LEFTOVER)
 243             size = 2 * size;
 244         }
 245       else
 246         {
 247           size = 2 * size;
 248           if (size == 0)
 249             /* Wraparound.  */
 250             goto fail1;
 251           if (rof->auxmap != NULL)
 252             munmap (rof->auxmap, rof->auxmap_length);
 253         }
 254       rof->auxmap = (void *) mmap ((void *) 0, size, PROT_READ | PROT_WRITE,
 255                                    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 256       if (rof->auxmap == (void *) -1)
 257         {
 258           close (fd);
 259           return -1;
 260         }
 261       rof->auxmap_length = size;
 262       rof->auxmap_start = (unsigned long) rof->auxmap;
 263       rof->auxmap_end = rof->auxmap_start + size;
 264       rof->buffer = (char *) rof->auxmap;
 265      retry:
 266       /* Restart.  */
 267       if (lseek (fd, 0, SEEK_SET) < 0)
 268         {
 269           close (fd);
 270           fd = open (filename, O_RDONLY | O_CLOEXEC);
 271           if (fd < 0)
 272             goto fail2;
 273         }
 274     }
 275  fail1:
 276   close (fd);
 277  fail2:
 278   if (rof->auxmap != NULL)
 279     munmap (rof->auxmap, rof->auxmap_length);
 280   return -1;
 281 }
 282 
 283 /* Return the next byte from a read-only file stream without consuming it,
 284    or -1 at EOF.  */
 285 static int
 286 rof_peekchar (struct rofile *rof)
     /* [previous][next][first][last][top][bottom][index][help] */
 287 {
 288   if (rof->position == rof->filled)
 289     {
 290       rof->eof_seen = 1;
 291       return -1;
 292     }
 293   return (unsigned char) rof->buffer[rof->position];
 294 }
 295 
 296 /* Return the next byte from a read-only file stream, or -1 at EOF.  */
 297 static int
 298 rof_getchar (struct rofile *rof)
     /* [previous][next][first][last][top][bottom][index][help] */
 299 {
 300   int c = rof_peekchar (rof);
 301   if (c >= 0)
 302     rof->position++;
 303   return c;
 304 }
 305 
 306 /* Parse an unsigned hexadecimal number from a read-only file stream.  */
 307 static int
 308 rof_scanf_lx (struct rofile *rof, unsigned long *valuep)
     /* [previous][next][first][last][top][bottom][index][help] */
 309 {
 310   unsigned long value = 0;
 311   unsigned int numdigits = 0;
 312   for (;;)
 313     {
 314       int c = rof_peekchar (rof);
 315       if (c >= '0' && c <= '9')
 316         value = (value << 4) + (c - '0');
 317       else if (c >= 'A' && c <= 'F')
 318         value = (value << 4) + (c - 'A' + 10);
 319       else if (c >= 'a' && c <= 'f')
 320         value = (value << 4) + (c - 'a' + 10);
 321       else
 322         break;
 323       rof_getchar (rof);
 324       numdigits++;
 325     }
 326   if (numdigits == 0)
 327     return -1;
 328   *valuep = value;
 329   return 0;
 330 }
 331 
 332 /* Close a read-only file stream.  */
 333 static void
 334 rof_close (struct rofile *rof)
     /* [previous][next][first][last][top][bottom][index][help] */
 335 {
 336   if (rof->auxmap != NULL)
 337     munmap (rof->auxmap, rof->auxmap_length);
 338 }
 339 
 340 #endif
 341 
 342 
 343 /* Support for reading the info from a text file in the /proc file system.  */
 344 
 345 #if defined __linux__ || defined __ANDROID__ || (defined __FreeBSD_kernel__ && !defined __FreeBSD__) /* || defined __CYGWIN__ */
 346 /* GNU/kFreeBSD mounts /proc as linprocfs, which looks like a Linux /proc
 347    file system.  */
 348 
 349 static int
 350 vma_iterate_proc (vma_iterate_callback_fn callback, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 351 {
 352   struct rofile rof;
 353 
 354   /* Open the current process' maps file.  It describes one VMA per line.  */
 355   if (rof_open (&rof, "/proc/self/maps") >= 0)
 356     {
 357       unsigned long auxmap_start = rof.auxmap_start;
 358       unsigned long auxmap_end = rof.auxmap_end;
 359 
 360       for (;;)
 361         {
 362           unsigned long start, end;
 363           unsigned int flags;
 364           int c;
 365 
 366           /* Parse one line.  First start and end.  */
 367           if (!(rof_scanf_lx (&rof, &start) >= 0
 368                 && rof_getchar (&rof) == '-'
 369                 && rof_scanf_lx (&rof, &end) >= 0))
 370             break;
 371           /* Then the flags.  */
 372           do
 373             c = rof_getchar (&rof);
 374           while (c == ' ');
 375           flags = 0;
 376           if (c == 'r')
 377             flags |= VMA_PROT_READ;
 378           c = rof_getchar (&rof);
 379           if (c == 'w')
 380             flags |= VMA_PROT_WRITE;
 381           c = rof_getchar (&rof);
 382           if (c == 'x')
 383             flags |= VMA_PROT_EXECUTE;
 384           while (c = rof_getchar (&rof), c != -1 && c != '\n')
 385             ;
 386 
 387           if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
 388             {
 389               /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
 390                  = [start,auxmap_start-1] u [auxmap_end,end-1].  */
 391               if (start < auxmap_start)
 392                 if (callback (data, start, auxmap_start, flags))
 393                   break;
 394               if (auxmap_end - 1 < end - 1)
 395                 if (callback (data, auxmap_end, end, flags))
 396                   break;
 397             }
 398           else
 399             {
 400               if (callback (data, start, end, flags))
 401                 break;
 402             }
 403         }
 404       rof_close (&rof);
 405       return 0;
 406     }
 407 
 408   return -1;
 409 }
 410 
 411 #elif defined __FreeBSD__ || defined __DragonFly__ || defined __NetBSD__
 412 
 413 static int
 414 vma_iterate_proc (vma_iterate_callback_fn callback, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 415 {
 416   struct rofile rof;
 417 
 418   /* Open the current process' maps file.  It describes one VMA per line.  */
 419   if (rof_open (&rof, "/proc/curproc/map") >= 0)
 420     {
 421       unsigned long auxmap_start = rof.auxmap_start;
 422       unsigned long auxmap_end = rof.auxmap_end;
 423 
 424       for (;;)
 425         {
 426           unsigned long start, end;
 427           unsigned int flags;
 428           int c;
 429 
 430           /* Parse one line.  First start.  */
 431           if (!(rof_getchar (&rof) == '0'
 432                 && rof_getchar (&rof) == 'x'
 433                 && rof_scanf_lx (&rof, &start) >= 0))
 434             break;
 435           while (c = rof_peekchar (&rof), c == ' ' || c == '\t')
 436             rof_getchar (&rof);
 437           /* Then end.  */
 438           if (!(rof_getchar (&rof) == '0'
 439                 && rof_getchar (&rof) == 'x'
 440                 && rof_scanf_lx (&rof, &end) >= 0))
 441             break;
 442 # if defined __FreeBSD__ || defined __DragonFly__
 443           /* Then the resident pages count.  */
 444           do
 445             c = rof_getchar (&rof);
 446           while (c == ' ');
 447           do
 448             c = rof_getchar (&rof);
 449           while (c != -1 && c != '\n' && c != ' ');
 450           /* Then the private resident pages count.  */
 451           do
 452             c = rof_getchar (&rof);
 453           while (c == ' ');
 454           do
 455             c = rof_getchar (&rof);
 456           while (c != -1 && c != '\n' && c != ' ');
 457           /* Then some kernel address.  */
 458           do
 459             c = rof_getchar (&rof);
 460           while (c == ' ');
 461           do
 462             c = rof_getchar (&rof);
 463           while (c != -1 && c != '\n' && c != ' ');
 464 # endif
 465           /* Then the flags.  */
 466           do
 467             c = rof_getchar (&rof);
 468           while (c == ' ');
 469           flags = 0;
 470           if (c == 'r')
 471             flags |= VMA_PROT_READ;
 472           c = rof_getchar (&rof);
 473           if (c == 'w')
 474             flags |= VMA_PROT_WRITE;
 475           c = rof_getchar (&rof);
 476           if (c == 'x')
 477             flags |= VMA_PROT_EXECUTE;
 478           while (c = rof_getchar (&rof), c != -1 && c != '\n')
 479             ;
 480 
 481           if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
 482             {
 483               /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
 484                  = [start,auxmap_start-1] u [auxmap_end,end-1].  */
 485               if (start < auxmap_start)
 486                 if (callback (data, start, auxmap_start, flags))
 487                   break;
 488               if (auxmap_end - 1 < end - 1)
 489                 if (callback (data, auxmap_end, end, flags))
 490                   break;
 491             }
 492           else
 493             {
 494               if (callback (data, start, end, flags))
 495                 break;
 496             }
 497         }
 498       rof_close (&rof);
 499       return 0;
 500     }
 501 
 502   return -1;
 503 }
 504 
 505 #elif defined __minix
 506 
 507 static int
 508 vma_iterate_proc (vma_iterate_callback_fn callback, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 509 {
 510   char fnamebuf[6+10+4+1];
 511   char *fname;
 512   struct rofile rof;
 513 
 514   /* Construct fname = sprintf (fnamebuf+i, "/proc/%u/map", getpid ()).  */
 515   fname = fnamebuf + sizeof (fnamebuf) - (4 + 1);
 516   memcpy (fname, "/map", 4 + 1);
 517   {
 518     unsigned int value = getpid ();
 519     do
 520       *--fname = (value % 10) + '0';
 521     while ((value = value / 10) > 0);
 522   }
 523   fname -= 6;
 524   memcpy (fname, "/proc/", 6);
 525 
 526   /* Open the current process' maps file.  It describes one VMA per line.  */
 527   if (rof_open (&rof, fname) >= 0)
 528     {
 529       unsigned long auxmap_start = rof.auxmap_start;
 530       unsigned long auxmap_end = rof.auxmap_end;
 531 
 532       for (;;)
 533         {
 534           unsigned long start, end;
 535           unsigned int flags;
 536           int c;
 537 
 538           /* Parse one line.  First start and end.  */
 539           if (!(rof_scanf_lx (&rof, &start) >= 0
 540                 && rof_getchar (&rof) == '-'
 541                 && rof_scanf_lx (&rof, &end) >= 0))
 542             break;
 543           /* Then the flags.  */
 544           do
 545             c = rof_getchar (&rof);
 546           while (c == ' ');
 547           flags = 0;
 548           if (c == 'r')
 549             flags |= VMA_PROT_READ;
 550           c = rof_getchar (&rof);
 551           if (c == 'w')
 552             flags |= VMA_PROT_WRITE;
 553           c = rof_getchar (&rof);
 554           if (c == 'x')
 555             flags |= VMA_PROT_EXECUTE;
 556           while (c = rof_getchar (&rof), c != -1 && c != '\n')
 557             ;
 558 
 559           if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
 560             {
 561               /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
 562                  = [start,auxmap_start-1] u [auxmap_end,end-1].  */
 563               if (start < auxmap_start)
 564                 if (callback (data, start, auxmap_start, flags))
 565                   break;
 566               if (auxmap_end - 1 < end - 1)
 567                 if (callback (data, auxmap_end, end, flags))
 568                   break;
 569             }
 570           else
 571             {
 572               if (callback (data, start, end, flags))
 573                 break;
 574             }
 575         }
 576       rof_close (&rof);
 577       return 0;
 578     }
 579 
 580   return -1;
 581 }
 582 
 583 #else
 584 
 585 static inline int
 586 vma_iterate_proc (vma_iterate_callback_fn callback, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 587 {
 588   return -1;
 589 }
 590 
 591 #endif
 592 
 593 
 594 /* Support for reading the info from the BSD sysctl() system call.  */
 595 
 596 #if (defined __FreeBSD__ || defined __FreeBSD_kernel__) && defined KERN_PROC_VMMAP /* FreeBSD >= 7.1 */
 597 
 598 static int
 599 vma_iterate_bsd (vma_iterate_callback_fn callback, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 600 {
 601   /* Documentation: https://www.freebsd.org/cgi/man.cgi?sysctl(3)  */
 602   int info_path[] = { CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid () };
 603   size_t len;
 604   size_t pagesize;
 605   size_t memneed;
 606   void *auxmap;
 607   unsigned long auxmap_start;
 608   unsigned long auxmap_end;
 609   char *mem;
 610   char *p;
 611   char *p_end;
 612 
 613   len = 0;
 614   if (sysctl (info_path, 4, NULL, &len, NULL, 0) < 0)
 615     return -1;
 616   /* Allow for small variations over time.  In a multithreaded program
 617      new VMAs can be allocated at any moment.  */
 618   len = 2 * len + 200;
 619   /* Allocate memneed bytes of memory.
 620      We cannot use alloca here, because not much stack space is guaranteed.
 621      We also cannot use malloc here, because a malloc() call may call mmap()
 622      and thus pre-allocate available memory.
 623      So use mmap(), and ignore the resulting VMA.  */
 624   pagesize = getpagesize ();
 625   memneed = len;
 626   memneed = ((memneed - 1) / pagesize + 1) * pagesize;
 627   auxmap = (void *) mmap ((void *) 0, memneed, PROT_READ | PROT_WRITE,
 628                           MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 629   if (auxmap == (void *) -1)
 630     return -1;
 631   auxmap_start = (unsigned long) auxmap;
 632   auxmap_end = auxmap_start + memneed;
 633   mem = (char *) auxmap;
 634   if (sysctl (info_path, 4, mem, &len, NULL, 0) < 0)
 635     {
 636       munmap (auxmap, memneed);
 637       return -1;
 638     }
 639   p = mem;
 640   p_end = mem + len;
 641   while (p < p_end)
 642     {
 643       struct kinfo_vmentry *kve = (struct kinfo_vmentry *) p;
 644       unsigned long start = kve->kve_start;
 645       unsigned long end = kve->kve_end;
 646       unsigned int flags = 0;
 647       if (kve->kve_protection & KVME_PROT_READ)
 648         flags |= VMA_PROT_READ;
 649       if (kve->kve_protection & KVME_PROT_WRITE)
 650         flags |= VMA_PROT_WRITE;
 651       if (kve->kve_protection & KVME_PROT_EXEC)
 652         flags |= VMA_PROT_EXECUTE;
 653       if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
 654         {
 655           /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
 656              = [start,auxmap_start-1] u [auxmap_end,end-1].  */
 657           if (start < auxmap_start)
 658             if (callback (data, start, auxmap_start, flags))
 659               break;
 660           if (auxmap_end - 1 < end - 1)
 661             if (callback (data, auxmap_end, end, flags))
 662               break;
 663         }
 664       else
 665         {
 666           if (callback (data, start, end, flags))
 667             break;
 668         }
 669       p += kve->kve_structsize;
 670     }
 671   munmap (auxmap, memneed);
 672   return 0;
 673 }
 674 
 675 #elif defined __NetBSD__ && defined VM_PROC_MAP /* NetBSD >= 8.0 */
 676 
 677 static int
 678 vma_iterate_bsd (vma_iterate_callback_fn callback, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 679 {
 680   /* Documentation: https://man.netbsd.org/man/sysctl+7  */
 681   unsigned int entry_size =
 682     /* If we wanted to have the path of each entry, we would need
 683        sizeof (struct kinfo_vmentry).  But we need only the non-string
 684        parts of each entry.  */
 685     offsetof (struct kinfo_vmentry, kve_path);
 686   int info_path[] = { CTL_VM, VM_PROC, VM_PROC_MAP, getpid (), entry_size };
 687   size_t len;
 688   size_t pagesize;
 689   size_t memneed;
 690   void *auxmap;
 691   unsigned long auxmap_start;
 692   unsigned long auxmap_end;
 693   char *mem;
 694   char *p;
 695   char *p_end;
 696 
 697   len = 0;
 698   if (sysctl (info_path, 5, NULL, &len, NULL, 0) < 0)
 699     return -1;
 700   /* Allow for small variations over time.  In a multithreaded program
 701      new VMAs can be allocated at any moment.  */
 702   len = 2 * len + 10 * entry_size;
 703   /* But the system call rejects lengths > 1 MB.  */
 704   if (len > 0x100000)
 705     len = 0x100000;
 706   /* And the system call causes a kernel panic if the length is not a multiple
 707      of entry_size.  */
 708   len = (len / entry_size) * entry_size;
 709   /* Allocate memneed bytes of memory.
 710      We cannot use alloca here, because not much stack space is guaranteed.
 711      We also cannot use malloc here, because a malloc() call may call mmap()
 712      and thus pre-allocate available memory.
 713      So use mmap(), and ignore the resulting VMA.  */
 714   pagesize = getpagesize ();
 715   memneed = len;
 716   memneed = ((memneed - 1) / pagesize + 1) * pagesize;
 717   auxmap = (void *) mmap ((void *) 0, memneed, PROT_READ | PROT_WRITE,
 718                           MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 719   if (auxmap == (void *) -1)
 720     return -1;
 721   auxmap_start = (unsigned long) auxmap;
 722   auxmap_end = auxmap_start + memneed;
 723   mem = (char *) auxmap;
 724   if (sysctl (info_path, 5, mem, &len, NULL, 0) < 0
 725       || len > 0x100000 - entry_size)
 726     {
 727       /* sysctl failed, or the list of VMAs is possibly truncated.  */
 728       munmap (auxmap, memneed);
 729       return -1;
 730     }
 731   p = mem;
 732   p_end = mem + len;
 733   while (p < p_end)
 734     {
 735       struct kinfo_vmentry *kve = (struct kinfo_vmentry *) p;
 736       unsigned long start = kve->kve_start;
 737       unsigned long end = kve->kve_end;
 738       unsigned int flags = 0;
 739       if (kve->kve_protection & KVME_PROT_READ)
 740         flags |= VMA_PROT_READ;
 741       if (kve->kve_protection & KVME_PROT_WRITE)
 742         flags |= VMA_PROT_WRITE;
 743       if (kve->kve_protection & KVME_PROT_EXEC)
 744         flags |= VMA_PROT_EXECUTE;
 745       if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
 746         {
 747           /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
 748              = [start,auxmap_start-1] u [auxmap_end,end-1].  */
 749           if (start < auxmap_start)
 750             if (callback (data, start, auxmap_start, flags))
 751               break;
 752           if (auxmap_end - 1 < end - 1)
 753             if (callback (data, auxmap_end, end, flags))
 754               break;
 755         }
 756       else
 757         {
 758           if (callback (data, start, end, flags))
 759             break;
 760         }
 761       p += entry_size;
 762     }
 763   munmap (auxmap, memneed);
 764   return 0;
 765 }
 766 
 767 #elif defined __OpenBSD__ && defined KERN_PROC_VMMAP /* OpenBSD >= 5.7 */
 768 
 769 static int
 770 vma_iterate_bsd (vma_iterate_callback_fn callback, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 771 {
 772   /* Documentation: https://man.openbsd.org/sysctl.2  */
 773   int info_path[] = { CTL_KERN, KERN_PROC_VMMAP, getpid () };
 774   size_t len;
 775   size_t pagesize;
 776   size_t memneed;
 777   void *auxmap;
 778   unsigned long auxmap_start;
 779   unsigned long auxmap_end;
 780   char *mem;
 781   char *p;
 782   char *p_end;
 783 
 784   len = 0;
 785   if (sysctl (info_path, 3, NULL, &len, NULL, 0) < 0)
 786     return -1;
 787   /* Allow for small variations over time.  In a multithreaded program
 788      new VMAs can be allocated at any moment.  */
 789   len = 2 * len + 10 * sizeof (struct kinfo_vmentry);
 790   /* But the system call rejects lengths > 64 KB.  */
 791   if (len > 0x10000)
 792     len = 0x10000;
 793   /* And the system call rejects lengths that are not a multiple of
 794      sizeof (struct kinfo_vmentry).  */
 795   len = (len / sizeof (struct kinfo_vmentry)) * sizeof (struct kinfo_vmentry);
 796   /* Allocate memneed bytes of memory.
 797      We cannot use alloca here, because not much stack space is guaranteed.
 798      We also cannot use malloc here, because a malloc() call may call mmap()
 799      and thus pre-allocate available memory.
 800      So use mmap(), and ignore the resulting VMA.  */
 801   pagesize = getpagesize ();
 802   memneed = len;
 803   memneed = ((memneed - 1) / pagesize + 1) * pagesize;
 804   auxmap = (void *) mmap ((void *) 0, memneed, PROT_READ | PROT_WRITE,
 805                           MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 806   if (auxmap == (void *) -1)
 807     return -1;
 808   auxmap_start = (unsigned long) auxmap;
 809   auxmap_end = auxmap_start + memneed;
 810   mem = (char *) auxmap;
 811   if (sysctl (info_path, 3, mem, &len, NULL, 0) < 0
 812       || len > 0x10000 - sizeof (struct kinfo_vmentry))
 813     {
 814       /* sysctl failed, or the list of VMAs is possibly truncated.  */
 815       munmap (auxmap, memneed);
 816       return -1;
 817     }
 818   p = mem;
 819   p_end = mem + len;
 820   while (p < p_end)
 821     {
 822       struct kinfo_vmentry *kve = (struct kinfo_vmentry *) p;
 823       unsigned long start = kve->kve_start;
 824       unsigned long end = kve->kve_end;
 825       unsigned int flags = 0;
 826       if (kve->kve_protection & KVE_PROT_READ)
 827         flags |= VMA_PROT_READ;
 828       if (kve->kve_protection & KVE_PROT_WRITE)
 829         flags |= VMA_PROT_WRITE;
 830       if (kve->kve_protection & KVE_PROT_EXEC)
 831         flags |= VMA_PROT_EXECUTE;
 832       if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
 833         {
 834           /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
 835              = [start,auxmap_start-1] u [auxmap_end,end-1].  */
 836           if (start < auxmap_start)
 837             if (callback (data, start, auxmap_start, flags))
 838               break;
 839           if (auxmap_end - 1 < end - 1)
 840             if (callback (data, auxmap_end, end, flags))
 841               break;
 842         }
 843       else
 844         {
 845           if (start != end)
 846             if (callback (data, start, end, flags))
 847               break;
 848         }
 849       p += sizeof (struct kinfo_vmentry);
 850     }
 851   munmap (auxmap, memneed);
 852   return 0;
 853 }
 854 
 855 #else
 856 
 857 static inline int
 858 vma_iterate_bsd (vma_iterate_callback_fn callback, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 859 {
 860   return -1;
 861 }
 862 
 863 #endif
 864 
 865 
 866 int
 867 vma_iterate (vma_iterate_callback_fn callback, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 868 {
 869 #if defined __linux__ || defined __ANDROID__ || defined __FreeBSD_kernel__ || defined __FreeBSD__ || defined __DragonFly__ || defined __NetBSD__ || defined __minix /* || defined __CYGWIN__ */
 870 
 871 # if defined __FreeBSD__
 872   /* On FreeBSD with procfs (but not GNU/kFreeBSD, which uses linprocfs), the
 873      function vma_iterate_proc does not return the virtual memory areas that
 874      were created by anonymous mmap.  See
 875      <https://svnweb.freebsd.org/base/head/sys/fs/procfs/procfs_map.c?view=markup>
 876      So use vma_iterate_proc only as a fallback.  */
 877   int retval = vma_iterate_bsd (callback, data);
 878   if (retval == 0)
 879       return 0;
 880 
 881   return vma_iterate_proc (callback, data);
 882 # else
 883   /* On the other platforms, try the /proc approach first, and the sysctl()
 884      as a fallback.  */
 885   int retval = vma_iterate_proc (callback, data);
 886   if (retval == 0)
 887       return 0;
 888 
 889   return vma_iterate_bsd (callback, data);
 890 # endif
 891 
 892 #elif defined __sgi || defined __osf__ /* IRIX, OSF/1 */
 893 
 894   size_t pagesize;
 895   char fnamebuf[6+10+1];
 896   char *fname;
 897   int fd;
 898   int nmaps;
 899   size_t memneed;
 900 # if HAVE_MAP_ANONYMOUS
 901 #  define zero_fd -1
 902 #  define map_flags MAP_ANONYMOUS
 903 # else
 904   int zero_fd;
 905 #  define map_flags 0
 906 # endif
 907   void *auxmap;
 908   unsigned long auxmap_start;
 909   unsigned long auxmap_end;
 910   prmap_t* maps;
 911   prmap_t* mp;
 912 
 913   pagesize = getpagesize ();
 914 
 915   /* Construct fname = sprintf (fnamebuf+i, "/proc/%u", getpid ()).  */
 916   fname = fnamebuf + sizeof (fnamebuf) - 1;
 917   *fname = '\0';
 918   {
 919     unsigned int value = getpid ();
 920     do
 921       *--fname = (value % 10) + '0';
 922     while ((value = value / 10) > 0);
 923   }
 924   fname -= 6;
 925   memcpy (fname, "/proc/", 6);
 926 
 927   fd = open (fname, O_RDONLY | O_CLOEXEC);
 928   if (fd < 0)
 929     return -1;
 930 
 931   if (ioctl (fd, PIOCNMAP, &nmaps) < 0)
 932     goto fail2;
 933 
 934   memneed = (nmaps + 10) * sizeof (prmap_t);
 935   /* Allocate memneed bytes of memory.
 936      We cannot use alloca here, because not much stack space is guaranteed.
 937      We also cannot use malloc here, because a malloc() call may call mmap()
 938      and thus pre-allocate available memory.
 939      So use mmap(), and ignore the resulting VMA.  */
 940   memneed = ((memneed - 1) / pagesize + 1) * pagesize;
 941 # if !HAVE_MAP_ANONYMOUS
 942   zero_fd = open ("/dev/zero", O_RDONLY | O_CLOEXEC, 0644);
 943   if (zero_fd < 0)
 944     goto fail2;
 945 # endif
 946   auxmap = (void *) mmap ((void *) 0, memneed, PROT_READ | PROT_WRITE,
 947                           map_flags | MAP_PRIVATE, zero_fd, 0);
 948 # if !HAVE_MAP_ANONYMOUS
 949   close (zero_fd);
 950 # endif
 951   if (auxmap == (void *) -1)
 952     goto fail2;
 953   auxmap_start = (unsigned long) auxmap;
 954   auxmap_end = auxmap_start + memneed;
 955   maps = (prmap_t *) auxmap;
 956 
 957   if (ioctl (fd, PIOCMAP, maps) < 0)
 958     goto fail1;
 959 
 960   for (mp = maps;;)
 961     {
 962       unsigned long start, end;
 963       unsigned int flags;
 964 
 965       start = (unsigned long) mp->pr_vaddr;
 966       end = start + mp->pr_size;
 967       if (start == 0 && end == 0)
 968         break;
 969       flags = 0;
 970       if (mp->pr_mflags & MA_READ)
 971         flags |= VMA_PROT_READ;
 972       if (mp->pr_mflags & MA_WRITE)
 973         flags |= VMA_PROT_WRITE;
 974       if (mp->pr_mflags & MA_EXEC)
 975         flags |= VMA_PROT_EXECUTE;
 976       mp++;
 977       if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
 978         {
 979           /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
 980              = [start,auxmap_start-1] u [auxmap_end,end-1].  */
 981           if (start < auxmap_start)
 982             if (callback (data, start, auxmap_start, flags))
 983               break;
 984           if (auxmap_end - 1 < end - 1)
 985             if (callback (data, auxmap_end, end, flags))
 986               break;
 987         }
 988       else
 989         {
 990           if (callback (data, start, end, flags))
 991             break;
 992         }
 993     }
 994   munmap (auxmap, memneed);
 995   close (fd);
 996   return 0;
 997 
 998  fail1:
 999   munmap (auxmap, memneed);
1000  fail2:
1001   close (fd);
1002   return -1;
1003 
1004 #elif defined __sun /* Solaris */
1005 
1006   /* Note: Solaris <sys/procfs.h> defines a different type prmap_t with
1007      _STRUCTURED_PROC than without! Here's a table of sizeof(prmap_t):
1008                                   32-bit   64-bit
1009          _STRUCTURED_PROC = 0       32       56
1010          _STRUCTURED_PROC = 1       96      104
1011      Therefore, if the include files provide the newer API, prmap_t has
1012      the bigger size, and thus you MUST use the newer API.  And if the
1013      include files provide the older API, prmap_t has the smaller size,
1014      and thus you MUST use the older API.  */
1015 
1016 # if defined PIOCNMAP && defined PIOCMAP
1017   /* We must use the older /proc interface.  */
1018 
1019   size_t pagesize;
1020   char fnamebuf[6+10+1];
1021   char *fname;
1022   int fd;
1023   int nmaps;
1024   size_t memneed;
1025 #  if HAVE_MAP_ANONYMOUS
1026 #   define zero_fd -1
1027 #   define map_flags MAP_ANONYMOUS
1028 #  else /* Solaris <= 7 */
1029   int zero_fd;
1030 #   define map_flags 0
1031 #  endif
1032   void *auxmap;
1033   unsigned long auxmap_start;
1034   unsigned long auxmap_end;
1035   prmap_t* maps;
1036   prmap_t* mp;
1037 
1038   pagesize = getpagesize ();
1039 
1040   /* Construct fname = sprintf (fnamebuf+i, "/proc/%u", getpid ()).  */
1041   fname = fnamebuf + sizeof (fnamebuf) - 1;
1042   *fname = '\0';
1043   {
1044     unsigned int value = getpid ();
1045     do
1046       *--fname = (value % 10) + '0';
1047     while ((value = value / 10) > 0);
1048   }
1049   fname -= 6;
1050   memcpy (fname, "/proc/", 6);
1051 
1052   fd = open (fname, O_RDONLY | O_CLOEXEC);
1053   if (fd < 0)
1054     return -1;
1055 
1056   if (ioctl (fd, PIOCNMAP, &nmaps) < 0)
1057     goto fail2;
1058 
1059   memneed = (nmaps + 10) * sizeof (prmap_t);
1060   /* Allocate memneed bytes of memory.
1061      We cannot use alloca here, because not much stack space is guaranteed.
1062      We also cannot use malloc here, because a malloc() call may call mmap()
1063      and thus pre-allocate available memory.
1064      So use mmap(), and ignore the resulting VMA.  */
1065   memneed = ((memneed - 1) / pagesize + 1) * pagesize;
1066 #  if !HAVE_MAP_ANONYMOUS
1067   zero_fd = open ("/dev/zero", O_RDONLY | O_CLOEXEC, 0644);
1068   if (zero_fd < 0)
1069     goto fail2;
1070 #  endif
1071   auxmap = (void *) mmap ((void *) 0, memneed, PROT_READ | PROT_WRITE,
1072                           map_flags | MAP_PRIVATE, zero_fd, 0);
1073 #  if !HAVE_MAP_ANONYMOUS
1074   close (zero_fd);
1075 #  endif
1076   if (auxmap == (void *) -1)
1077     goto fail2;
1078   auxmap_start = (unsigned long) auxmap;
1079   auxmap_end = auxmap_start + memneed;
1080   maps = (prmap_t *) auxmap;
1081 
1082   if (ioctl (fd, PIOCMAP, maps) < 0)
1083     goto fail1;
1084 
1085   for (mp = maps;;)
1086     {
1087       unsigned long start, end;
1088       unsigned int flags;
1089 
1090       start = (unsigned long) mp->pr_vaddr;
1091       end = start + mp->pr_size;
1092       if (start == 0 && end == 0)
1093         break;
1094       flags = 0;
1095       if (mp->pr_mflags & MA_READ)
1096         flags |= VMA_PROT_READ;
1097       if (mp->pr_mflags & MA_WRITE)
1098         flags |= VMA_PROT_WRITE;
1099       if (mp->pr_mflags & MA_EXEC)
1100         flags |= VMA_PROT_EXECUTE;
1101       mp++;
1102       if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
1103         {
1104           /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
1105              = [start,auxmap_start-1] u [auxmap_end,end-1].  */
1106           if (start < auxmap_start)
1107             if (callback (data, start, auxmap_start, flags))
1108               break;
1109           if (auxmap_end - 1 < end - 1)
1110             if (callback (data, auxmap_end, end, flags))
1111               break;
1112         }
1113       else
1114         {
1115           if (callback (data, start, end, flags))
1116             break;
1117         }
1118     }
1119   munmap (auxmap, memneed);
1120   close (fd);
1121   return 0;
1122 
1123  fail1:
1124   munmap (auxmap, memneed);
1125  fail2:
1126   close (fd);
1127   return -1;
1128 
1129 # else
1130   /* We must use the newer /proc interface.
1131      Documentation:
1132      https://docs.oracle.com/cd/E23824_01/html/821-1473/proc-4.html
1133      The contents of /proc/<pid>/map consists of records of type
1134      prmap_t.  These are different in 32-bit and 64-bit processes,
1135      but here we are fortunately accessing only the current process.  */
1136 
1137   size_t pagesize;
1138   char fnamebuf[6+10+4+1];
1139   char *fname;
1140   int fd;
1141   int nmaps;
1142   size_t memneed;
1143 #  if HAVE_MAP_ANONYMOUS
1144 #   define zero_fd -1
1145 #   define map_flags MAP_ANONYMOUS
1146 #  else /* Solaris <= 7 */
1147   int zero_fd;
1148 #   define map_flags 0
1149 #  endif
1150   void *auxmap;
1151   unsigned long auxmap_start;
1152   unsigned long auxmap_end;
1153   prmap_t* maps;
1154   prmap_t* maps_end;
1155   prmap_t* mp;
1156 
1157   pagesize = getpagesize ();
1158 
1159   /* Construct fname = sprintf (fnamebuf+i, "/proc/%u/map", getpid ()).  */
1160   fname = fnamebuf + sizeof (fnamebuf) - 1 - 4;
1161   memcpy (fname, "/map", 4 + 1);
1162   {
1163     unsigned int value = getpid ();
1164     do
1165       *--fname = (value % 10) + '0';
1166     while ((value = value / 10) > 0);
1167   }
1168   fname -= 6;
1169   memcpy (fname, "/proc/", 6);
1170 
1171   fd = open (fname, O_RDONLY | O_CLOEXEC);
1172   if (fd < 0)
1173     return -1;
1174 
1175   {
1176     struct stat statbuf;
1177     if (fstat (fd, &statbuf) < 0)
1178       goto fail2;
1179     nmaps = statbuf.st_size / sizeof (prmap_t);
1180   }
1181 
1182   memneed = (nmaps + 10) * sizeof (prmap_t);
1183   /* Allocate memneed bytes of memory.
1184      We cannot use alloca here, because not much stack space is guaranteed.
1185      We also cannot use malloc here, because a malloc() call may call mmap()
1186      and thus pre-allocate available memory.
1187      So use mmap(), and ignore the resulting VMA.  */
1188   memneed = ((memneed - 1) / pagesize + 1) * pagesize;
1189 #  if !HAVE_MAP_ANONYMOUS
1190   zero_fd = open ("/dev/zero", O_RDONLY | O_CLOEXEC, 0644);
1191   if (zero_fd < 0)
1192     goto fail2;
1193 #  endif
1194   auxmap = (void *) mmap ((void *) 0, memneed, PROT_READ | PROT_WRITE,
1195                           map_flags | MAP_PRIVATE, zero_fd, 0);
1196 #  if !HAVE_MAP_ANONYMOUS
1197   close (zero_fd);
1198 #  endif
1199   if (auxmap == (void *) -1)
1200     goto fail2;
1201   auxmap_start = (unsigned long) auxmap;
1202   auxmap_end = auxmap_start + memneed;
1203   maps = (prmap_t *) auxmap;
1204 
1205   /* Read up to memneed bytes from fd into maps.  */
1206   {
1207     size_t remaining = memneed;
1208     size_t total_read = 0;
1209     char *ptr = (char *) maps;
1210 
1211     do
1212       {
1213         size_t nread = read (fd, ptr, remaining);
1214         if (nread == (size_t)-1)
1215           {
1216             if (errno == EINTR)
1217               continue;
1218             goto fail1;
1219           }
1220         if (nread == 0)
1221           /* EOF */
1222           break;
1223         total_read += nread;
1224         ptr += nread;
1225         remaining -= nread;
1226       }
1227     while (remaining > 0);
1228 
1229     nmaps = (memneed - remaining) / sizeof (prmap_t);
1230     maps_end = maps + nmaps;
1231   }
1232 
1233   for (mp = maps; mp < maps_end; mp++)
1234     {
1235       unsigned long start, end;
1236       unsigned int flags;
1237 
1238       start = (unsigned long) mp->pr_vaddr;
1239       end = start + mp->pr_size;
1240       flags = 0;
1241       if (mp->pr_mflags & MA_READ)
1242         flags |= VMA_PROT_READ;
1243       if (mp->pr_mflags & MA_WRITE)
1244         flags |= VMA_PROT_WRITE;
1245       if (mp->pr_mflags & MA_EXEC)
1246         flags |= VMA_PROT_EXECUTE;
1247       if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
1248         {
1249           /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
1250              = [start,auxmap_start-1] u [auxmap_end,end-1].  */
1251           if (start < auxmap_start)
1252             if (callback (data, start, auxmap_start, flags))
1253               break;
1254           if (auxmap_end - 1 < end - 1)
1255             if (callback (data, auxmap_end, end, flags))
1256               break;
1257         }
1258       else
1259         {
1260           if (callback (data, start, end, flags))
1261             break;
1262         }
1263     }
1264   munmap (auxmap, memneed);
1265   close (fd);
1266   return 0;
1267 
1268  fail1:
1269   munmap (auxmap, memneed);
1270  fail2:
1271   close (fd);
1272   return -1;
1273 
1274 # endif
1275 
1276 #elif HAVE_PSTAT_GETPROCVM /* HP-UX */
1277 
1278   unsigned long pagesize = getpagesize ();
1279   int i;
1280 
1281   for (i = 0; ; i++)
1282     {
1283       struct pst_vm_status info;
1284       int ret = pstat_getprocvm (&info, sizeof (info), 0, i);
1285       if (ret < 0)
1286         return -1;
1287       if (ret == 0)
1288         break;
1289       {
1290         unsigned long start = info.pst_vaddr;
1291         unsigned long end = start + info.pst_length * pagesize;
1292         unsigned int flags = 0;
1293         if (info.pst_permission & PS_PROT_READ)
1294           flags |= VMA_PROT_READ;
1295         if (info.pst_permission & PS_PROT_WRITE)
1296           flags |= VMA_PROT_WRITE;
1297         if (info.pst_permission & PS_PROT_EXECUTE)
1298           flags |= VMA_PROT_EXECUTE;
1299 
1300         if (callback (data, start, end, flags))
1301           break;
1302       }
1303     }
1304 
1305 #elif defined __APPLE__ && defined __MACH__ /* Mac OS X */
1306 
1307   task_t task = mach_task_self ();
1308   vm_address_t address;
1309   vm_size_t size;
1310 
1311   for (address = VM_MIN_ADDRESS;; address += size)
1312     {
1313       int more;
1314       mach_port_t object_name;
1315       unsigned int flags;
1316       /* In Mac OS X 10.5, the types vm_address_t, vm_offset_t, vm_size_t have
1317          32 bits in 32-bit processes and 64 bits in 64-bit processes. Whereas
1318          mach_vm_address_t and mach_vm_size_t are always 64 bits large.
1319          Mac OS X 10.5 has three vm_region like methods:
1320            - vm_region. It has arguments that depend on whether the current
1321              process is 32-bit or 64-bit. When linking dynamically, this
1322              function exists only in 32-bit processes. Therefore we use it only
1323              in 32-bit processes.
1324            - vm_region_64. It has arguments that depend on whether the current
1325              process is 32-bit or 64-bit. It interprets a flavor
1326              VM_REGION_BASIC_INFO as VM_REGION_BASIC_INFO_64, which is
1327              dangerous since 'struct vm_region_basic_info_64' is larger than
1328              'struct vm_region_basic_info'; therefore let's write
1329              VM_REGION_BASIC_INFO_64 explicitly.
1330            - mach_vm_region. It has arguments that are 64-bit always. This
1331              function is useful when you want to access the VM of a process
1332              other than the current process.
1333          In 64-bit processes, we could use vm_region_64 or mach_vm_region.
1334          I choose vm_region_64 because it uses the same types as vm_region,
1335          resulting in less conditional code.  */
1336 # if defined __aarch64__ || defined __ppc64__ || defined __x86_64__
1337       struct vm_region_basic_info_64 info;
1338       mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
1339 
1340       more = (vm_region_64 (task, &address, &size, VM_REGION_BASIC_INFO_64,
1341                             (vm_region_info_t)&info, &info_count, &object_name)
1342               == KERN_SUCCESS);
1343 # else
1344       struct vm_region_basic_info info;
1345       mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
1346 
1347       more = (vm_region (task, &address, &size, VM_REGION_BASIC_INFO,
1348                          (vm_region_info_t)&info, &info_count, &object_name)
1349               == KERN_SUCCESS);
1350 # endif
1351       if (object_name != MACH_PORT_NULL)
1352         mach_port_deallocate (mach_task_self (), object_name);
1353       if (!more)
1354         break;
1355       flags = 0;
1356       if (info.protection & VM_PROT_READ)
1357         flags |= VMA_PROT_READ;
1358       if (info.protection & VM_PROT_WRITE)
1359         flags |= VMA_PROT_WRITE;
1360       if (info.protection & VM_PROT_EXECUTE)
1361         flags |= VMA_PROT_EXECUTE;
1362       if (callback (data, address, address + size, flags))
1363         break;
1364     }
1365   return 0;
1366 
1367 #elif defined __GNU__ /* GNU/Hurd */
1368 
1369   /* The Hurd has a /proc/self/maps that looks like the Linux one, but it
1370      lacks the VMAs created through anonymous mmap.  Therefore use the Mach
1371      API.
1372      Documentation:
1373      https://www.gnu.org/software/hurd/gnumach-doc/Memory-Attributes.html */
1374 
1375   task_t task = mach_task_self ();
1376   vm_address_t address;
1377   vm_size_t size;
1378 
1379   for (address = 0;; address += size)
1380     {
1381       vm_prot_t protection;
1382       vm_prot_t max_protection;
1383       vm_inherit_t inheritance;
1384       boolean_t shared;
1385       memory_object_name_t object_name;
1386       vm_offset_t offset;
1387       unsigned int flags;
1388 
1389       if (!(vm_region (task, &address, &size, &protection, &max_protection,
1390                          &inheritance, &shared, &object_name, &offset)
1391             == KERN_SUCCESS))
1392         break;
1393       mach_port_deallocate (task, object_name);
1394       flags = 0;
1395       if (protection & VM_PROT_READ)
1396         flags |= VMA_PROT_READ;
1397       if (protection & VM_PROT_WRITE)
1398         flags |= VMA_PROT_WRITE;
1399       if (protection & VM_PROT_EXECUTE)
1400         flags |= VMA_PROT_EXECUTE;
1401       if (callback (data, address, address + size, flags))
1402         break;
1403     }
1404   return 0;
1405 
1406 #elif defined _WIN32 || defined __CYGWIN__
1407   /* Windows platform.  Use the native Windows API.  */
1408 
1409   MEMORY_BASIC_INFORMATION info;
1410   uintptr_t address = 0;
1411 
1412   while (VirtualQuery ((void*)address, &info, sizeof(info)) == sizeof(info))
1413     {
1414       if (info.State != MEM_FREE)
1415         /* Ignore areas where info.State has the value MEM_RESERVE or,
1416            equivalently, info.Protect has the undocumented value 0.
1417            This is needed, so that on Cygwin, areas used by malloc() are
1418            distinguished from areas reserved for future malloc().  */
1419         if (info.State != MEM_RESERVE)
1420           {
1421             uintptr_t start, end;
1422             unsigned int flags;
1423 
1424             start = (uintptr_t)info.BaseAddress;
1425             end = start + info.RegionSize;
1426             switch (info.Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
1427               {
1428               case PAGE_READONLY:
1429                 flags = VMA_PROT_READ;
1430                 break;
1431               case PAGE_READWRITE:
1432               case PAGE_WRITECOPY:
1433                 flags = VMA_PROT_READ | VMA_PROT_WRITE;
1434                 break;
1435               case PAGE_EXECUTE:
1436                 flags = VMA_PROT_EXECUTE;
1437                 break;
1438               case PAGE_EXECUTE_READ:
1439                 flags = VMA_PROT_READ | VMA_PROT_EXECUTE;
1440                 break;
1441               case PAGE_EXECUTE_READWRITE:
1442               case PAGE_EXECUTE_WRITECOPY:
1443                 flags = VMA_PROT_READ | VMA_PROT_WRITE | VMA_PROT_EXECUTE;
1444                 break;
1445               case PAGE_NOACCESS:
1446               default:
1447                 flags = 0;
1448                 break;
1449               }
1450 
1451             if (callback (data, start, end, flags))
1452               break;
1453           }
1454       address = (uintptr_t)info.BaseAddress + info.RegionSize;
1455     }
1456   return 0;
1457 
1458 #elif defined __BEOS__ || defined __HAIKU__
1459   /* Use the BeOS specific API.  */
1460 
1461   area_info info;
1462   ssize_t cookie;
1463 
1464   cookie = 0;
1465   while (get_next_area_info (0, &cookie, &info) == B_OK)
1466     {
1467       unsigned long start, end;
1468       unsigned int flags;
1469 
1470       start = (unsigned long) info.address;
1471       end = start + info.size;
1472       flags = 0;
1473       if (info.protection & B_READ_AREA)
1474         flags |= VMA_PROT_READ | VMA_PROT_EXECUTE;
1475       if (info.protection & B_WRITE_AREA)
1476         flags |= VMA_PROT_WRITE;
1477 
1478       if (callback (data, start, end, flags))
1479         break;
1480     }
1481   return 0;
1482 
1483 #elif HAVE_MQUERY /* OpenBSD */
1484 
1485 # if defined __OpenBSD__
1486   /* Try sysctl() first.  It is more efficient than the mquery() loop below
1487      and also provides the flags.  */
1488   {
1489     int retval = vma_iterate_bsd (callback, data);
1490     if (retval == 0)
1491       return 0;
1492   }
1493 # endif
1494 
1495   {
1496     uintptr_t pagesize;
1497     uintptr_t address;
1498     int /*bool*/ address_known_mapped;
1499 
1500     pagesize = getpagesize ();
1501     /* Avoid calling mquery with a NULL first argument, because this argument
1502        value has a specific meaning.  We know the NULL page is unmapped.  */
1503     address = pagesize;
1504     address_known_mapped = 0;
1505     for (;;)
1506       {
1507         /* Test whether the page at address is mapped.  */
1508         if (address_known_mapped
1509             || mquery ((void *) address, pagesize, 0, MAP_FIXED, -1, 0)
1510                == (void *) -1)
1511           {
1512             /* The page at address is mapped.
1513                This is the start of an interval.  */
1514             uintptr_t start = address;
1515             uintptr_t end;
1516 
1517             /* Find the end of the interval.  */
1518             end = (uintptr_t) mquery ((void *) address, pagesize, 0, 0, -1, 0);
1519             if (end == (uintptr_t) (void *) -1)
1520               end = 0; /* wrap around */
1521             address = end;
1522 
1523             /* It's too complicated to find out about the flags.
1524                Just pass 0.  */
1525             if (callback (data, start, end, 0))
1526               break;
1527 
1528             if (address < pagesize) /* wrap around? */
1529               break;
1530           }
1531         /* Here we know that the page at address is unmapped.  */
1532         {
1533           uintptr_t query_size = pagesize;
1534 
1535           address += pagesize;
1536 
1537           /* Query larger and larger blocks, to get through the unmapped address
1538              range with few mquery() calls.  */
1539           for (;;)
1540             {
1541               if (2 * query_size > query_size)
1542                 query_size = 2 * query_size;
1543               if (address + query_size - 1 < query_size) /* wrap around? */
1544                 {
1545                   address_known_mapped = 0;
1546                   break;
1547                 }
1548               if (mquery ((void *) address, query_size, 0, MAP_FIXED, -1, 0)
1549                   == (void *) -1)
1550                 {
1551                   /* Not all the interval [address .. address + query_size - 1]
1552                      is unmapped.  */
1553                   address_known_mapped = (query_size == pagesize);
1554                   break;
1555                 }
1556               /* The interval [address .. address + query_size - 1] is
1557                  unmapped.  */
1558               address += query_size;
1559             }
1560           /* Reduce the query size again, to determine the precise size of the
1561              unmapped interval that starts at address.  */
1562           while (query_size > pagesize)
1563             {
1564               query_size = query_size / 2;
1565               if (address + query_size - 1 >= query_size)
1566                 {
1567                   if (mquery ((void *) address, query_size, 0, MAP_FIXED, -1, 0)
1568                       != (void *) -1)
1569                     {
1570                       /* The interval [address .. address + query_size - 1] is
1571                          unmapped.  */
1572                       address += query_size;
1573                       address_known_mapped = 0;
1574                     }
1575                   else
1576                     address_known_mapped = (query_size == pagesize);
1577                 }
1578             }
1579           /* Here again query_size = pagesize, and
1580              either address + pagesize - 1 < pagesize, or
1581              mquery ((void *) address, pagesize, 0, MAP_FIXED, -1, 0) fails.
1582              So, the unmapped area ends at address.  */
1583         }
1584         if (address + pagesize - 1 < pagesize) /* wrap around? */
1585           break;
1586       }
1587     return 0;
1588   }
1589 
1590 #else
1591 
1592   /* Not implemented.  */
1593   return -1;
1594 
1595 #endif
1596 }
1597 
1598 
1599 #ifdef TEST
1600 
1601 #include <stdio.h>
1602 
1603 /* Output the VMAs of the current process in a format similar to the Linux
1604    /proc/$pid/maps file.  */
1605 
1606 static int
1607 vma_iterate_callback (void *data, uintptr_t start, uintptr_t end,
     /* [previous][next][first][last][top][bottom][index][help] */
1608                       unsigned int flags)
1609 {
1610   printf ("%08lx-%08lx %c%c%c\n",
1611           (unsigned long) start, (unsigned long) end,
1612           flags & VMA_PROT_READ ? 'r' : '-',
1613           flags & VMA_PROT_WRITE ? 'w' : '-',
1614           flags & VMA_PROT_EXECUTE ? 'x' : '-');
1615   return 0;
1616 }
1617 
1618 int
1619 main ()
     /* [previous][next][first][last][top][bottom][index][help] */
1620 {
1621   vma_iterate (vma_iterate_callback, NULL);
1622 
1623   /* Let the user interactively look at the /proc file system.  */
1624   sleep (10);
1625 
1626   return 0;
1627 }
1628 
1629 /*
1630  * Local Variables:
1631  * compile-command: "gcc -ggdb -DTEST -Wall -I.. vma-iter.c"
1632  * End:
1633  */
1634 
1635 #endif /* TEST */

/* [previous][next][first][last][top][bottom][index][help] */