(root)/
m4-1.4.19/
tests/
vma-iter.c
       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)
     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)
     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)
     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)
     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)
     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)
     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)
     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)
     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)
     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)
     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)
     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)
     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)
     859  {
     860    return -1;
     861  }
     862  
     863  #endif
     864  
     865  
     866  int
     867  vma_iterate (vma_iterate_callback_fn callback, void *data)
     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,
    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 ()
    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 */