summaryrefslogtreecommitdiff
path: root/lib/vma-iter.c
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2017-10-08 17:50:16 +0200
committerBruno Haible <bruno@clisp.org>2017-10-08 17:50:16 +0200
commit75548d51922c6aff6e408af5b31bcd64e2e7d521 (patch)
tree6dfab3291c73177acbc82e1fd8337a3c94354e5f /lib/vma-iter.c
parent63b88b1292ff77445b0750ff60f7593bc4baa69a (diff)
downloadgnulib-75548d51922c6aff6e408af5b31bcd64e2e7d521.tar.gz
vma-iter: Improve support for FreeBSD.
* lib/vma-iter.c (vma_iterate_proc): New function, extracted from vma_iterate. (vma_iterate): Use it. For FreeBSD, try vma_iterate_bsd first.
Diffstat (limited to 'lib/vma-iter.c')
-rw-r--r--lib/vma-iter.c336
1 files changed, 189 insertions, 147 deletions
diff --git a/lib/vma-iter.c b/lib/vma-iter.c
index d8575ce16f..0845867566 100644
--- a/lib/vma-iter.c
+++ b/lib/vma-iter.c
@@ -331,6 +331,179 @@ rof_close (struct rofile *rof)
#endif
+/* Support for reading the info from a text file in the /proc file system. */
+
+# if defined __linux__ || (defined __FreeBSD_kernel__ && !defined __FreeBSD__) /* || defined __CYGWIN__ */
+/* GNU/kFreeBSD mounts /proc as linprocfs, which looks like a Linux /proc
+ file system. */
+
+static int
+vma_iterate_proc (vma_iterate_callback_fn callback, void *data)
+{
+ struct rofile rof;
+
+ /* Open the current process' maps file. It describes one VMA per line. */
+ if (rof_open (&rof, "/proc/self/maps") >= 0)
+ {
+ unsigned long auxmap_start = rof.auxmap_start;
+ unsigned long auxmap_end = rof.auxmap_end;
+
+ for (;;)
+ {
+ unsigned long start, end;
+ unsigned int flags;
+ int c;
+
+ /* Parse one line. First start and end. */
+ if (!(rof_scanf_lx (&rof, &start) >= 0
+ && rof_getchar (&rof) == '-'
+ && rof_scanf_lx (&rof, &end) >= 0))
+ break;
+ /* Then the flags. */
+ do
+ c = rof_getchar (&rof);
+ while (c == ' ');
+ flags = 0;
+ if (c == 'r')
+ flags |= VMA_PROT_READ;
+ c = rof_getchar (&rof);
+ if (c == 'w')
+ flags |= VMA_PROT_WRITE;
+ c = rof_getchar (&rof);
+ if (c == 'x')
+ flags |= VMA_PROT_EXECUTE;
+ while (c = rof_getchar (&rof), c != -1 && c != '\n')
+ ;
+
+ if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
+ {
+ /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
+ = [start,auxmap_start-1] u [auxmap_end,end-1]. */
+ if (start < auxmap_start)
+ if (callback (data, start, auxmap_start, flags))
+ break;
+ if (auxmap_end - 1 < end - 1)
+ if (callback (data, auxmap_end, end, flags))
+ break;
+ }
+ else
+ {
+ if (callback (data, start, end, flags))
+ break;
+ }
+ }
+ rof_close (&rof);
+ return 0;
+ }
+
+ return -1;
+}
+
+#elif defined __FreeBSD__ || defined __DragonFly__ || defined __NetBSD__
+
+static int
+vma_iterate_proc (vma_iterate_callback_fn callback, void *data)
+{
+ struct rofile rof;
+
+ /* Open the current process' maps file. It describes one VMA per line. */
+ if (rof_open (&rof, "/proc/curproc/map") >= 0)
+ {
+ unsigned long auxmap_start = rof.auxmap_start;
+ unsigned long auxmap_end = rof.auxmap_end;
+
+ for (;;)
+ {
+ unsigned long start, end;
+ unsigned int flags;
+ int c;
+
+ /* Parse one line. First start. */
+ if (!(rof_getchar (&rof) == '0'
+ && rof_getchar (&rof) == 'x'
+ && rof_scanf_lx (&rof, &start) >= 0))
+ break;
+ while (c = rof_peekchar (&rof), c == ' ' || c == '\t')
+ rof_getchar (&rof);
+ /* Then end. */
+ if (!(rof_getchar (&rof) == '0'
+ && rof_getchar (&rof) == 'x'
+ && rof_scanf_lx (&rof, &end) >= 0))
+ break;
+# if defined __FreeBSD__ || defined __DragonFly__
+ /* Then the resident pages count. */
+ do
+ c = rof_getchar (&rof);
+ while (c == ' ');
+ do
+ c = rof_getchar (&rof);
+ while (c != -1 && c != '\n' && c != ' ');
+ /* Then the private resident pages count. */
+ do
+ c = rof_getchar (&rof);
+ while (c == ' ');
+ do
+ c = rof_getchar (&rof);
+ while (c != -1 && c != '\n' && c != ' ');
+ /* Then some kernel address. */
+ do
+ c = rof_getchar (&rof);
+ while (c == ' ');
+ do
+ c = rof_getchar (&rof);
+ while (c != -1 && c != '\n' && c != ' ');
+# endif
+ /* Then the flags. */
+ do
+ c = rof_getchar (&rof);
+ while (c == ' ');
+ flags = 0;
+ if (c == 'r')
+ flags |= VMA_PROT_READ;
+ c = rof_getchar (&rof);
+ if (c == 'w')
+ flags |= VMA_PROT_WRITE;
+ c = rof_getchar (&rof);
+ if (c == 'x')
+ flags |= VMA_PROT_EXECUTE;
+ while (c = rof_getchar (&rof), c != -1 && c != '\n')
+ ;
+
+ if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
+ {
+ /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
+ = [start,auxmap_start-1] u [auxmap_end,end-1]. */
+ if (start < auxmap_start)
+ if (callback (data, start, auxmap_start, flags))
+ break;
+ if (auxmap_end - 1 < end - 1)
+ if (callback (data, auxmap_end, end, flags))
+ break;
+ }
+ else
+ {
+ if (callback (data, start, end, flags))
+ break;
+ }
+ }
+ rof_close (&rof);
+ return 0;
+ }
+
+ return -1;
+}
+
+#else
+
+static inline int
+vma_iterate_proc (vma_iterate_callback_fn callback, void *data)
+{
+ return -1;
+}
+
+#endif
+
+
/* Support for reading the info from the BSD sysctl() system call. */
#if (defined __FreeBSD__ || defined __FreeBSD_kernel__) && defined KERN_PROC_VMMAP /* FreeBSD >= 7.1 */
@@ -606,159 +779,28 @@ vma_iterate_bsd (vma_iterate_callback_fn callback, void *data)
int
vma_iterate (vma_iterate_callback_fn callback, void *data)
{
-#if defined __linux__ || (defined __FreeBSD_kernel__ && !defined __FreeBSD__) /* || defined __CYGWIN__ */
- /* GNU/kFreeBSD mounts /proc as linprocfs, which looks like a Linux /proc
- file system. */
-
- struct rofile rof;
-
- /* Open the current process' maps file. It describes one VMA per line. */
- if (rof_open (&rof, "/proc/self/maps") >= 0)
- {
- unsigned long auxmap_start = rof.auxmap_start;
- unsigned long auxmap_end = rof.auxmap_end;
-
- for (;;)
- {
- unsigned long start, end;
- unsigned int flags;
- int c;
-
- /* Parse one line. First start and end. */
- if (!(rof_scanf_lx (&rof, &start) >= 0
- && rof_getchar (&rof) == '-'
- && rof_scanf_lx (&rof, &end) >= 0))
- break;
- /* Then the flags. */
- do
- c = rof_getchar (&rof);
- while (c == ' ');
- flags = 0;
- if (c == 'r')
- flags |= VMA_PROT_READ;
- c = rof_getchar (&rof);
- if (c == 'w')
- flags |= VMA_PROT_WRITE;
- c = rof_getchar (&rof);
- if (c == 'x')
- flags |= VMA_PROT_EXECUTE;
- while (c = rof_getchar (&rof), c != -1 && c != '\n')
- ;
+#if defined __linux__ || defined __FreeBSD_kernel__ || defined __FreeBSD__ || defined __DragonFly__ || defined __NetBSD__ /* || defined __CYGWIN__ */
- if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
- {
- /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
- = [start,auxmap_start-1] u [auxmap_end,end-1]. */
- if (start < auxmap_start)
- if (callback (data, start, auxmap_start, flags))
- break;
- if (auxmap_end - 1 < end - 1)
- if (callback (data, auxmap_end, end, flags))
- break;
- }
- else
- {
- if (callback (data, start, end, flags))
- break;
- }
- }
- rof_close (&rof);
+# if defined __FreeBSD__
+ /* On FreeBSD with procfs (but not GNU/kFreeBSD, which uses libprocfs), the
+ function vma_iterate_proc does not return the virtual memory areas that
+ were created by anonymous mmap. See
+ <https://svnweb.freebsd.org/base/head/sys/fs/procfs/procfs_map.c?view=markup>
+ So use vma_iterate_proc only as a fallback. */
+ int retval = vma_iterate_bsd (callback, data);
+ if (retval == 0)
return 0;
- }
-
- /* Fallback if /proc is not accessible: Use sysctl(). */
- return vma_iterate_bsd (callback, data);
-
-#elif defined __FreeBSD__ || defined __DragonFly__ || defined __NetBSD__
- struct rofile rof;
-
- /* Open the current process' maps file. It describes one VMA per line. */
- if (rof_open (&rof, "/proc/curproc/map") >= 0)
- {
- unsigned long auxmap_start = rof.auxmap_start;
- unsigned long auxmap_end = rof.auxmap_end;
-
- for (;;)
- {
- unsigned long start, end;
- unsigned int flags;
- int c;
-
- /* Parse one line. First start. */
- if (!(rof_getchar (&rof) == '0'
- && rof_getchar (&rof) == 'x'
- && rof_scanf_lx (&rof, &start) >= 0))
- break;
- while (c = rof_peekchar (&rof), c == ' ' || c == '\t')
- rof_getchar (&rof);
- /* Then end. */
- if (!(rof_getchar (&rof) == '0'
- && rof_getchar (&rof) == 'x'
- && rof_scanf_lx (&rof, &end) >= 0))
- break;
-# if defined __FreeBSD__ || defined __DragonFly__
- /* Then the resident pages count. */
- do
- c = rof_getchar (&rof);
- while (c == ' ');
- do
- c = rof_getchar (&rof);
- while (c != -1 && c != '\n' && c != ' ');
- /* Then the private resident pages count. */
- do
- c = rof_getchar (&rof);
- while (c == ' ');
- do
- c = rof_getchar (&rof);
- while (c != -1 && c != '\n' && c != ' ');
- /* Then some kernel address. */
- do
- c = rof_getchar (&rof);
- while (c == ' ');
- do
- c = rof_getchar (&rof);
- while (c != -1 && c != '\n' && c != ' ');
-# endif
- /* Then the flags. */
- do
- c = rof_getchar (&rof);
- while (c == ' ');
- flags = 0;
- if (c == 'r')
- flags |= VMA_PROT_READ;
- c = rof_getchar (&rof);
- if (c == 'w')
- flags |= VMA_PROT_WRITE;
- c = rof_getchar (&rof);
- if (c == 'x')
- flags |= VMA_PROT_EXECUTE;
- while (c = rof_getchar (&rof), c != -1 && c != '\n')
- ;
-
- if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
- {
- /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
- = [start,auxmap_start-1] u [auxmap_end,end-1]. */
- if (start < auxmap_start)
- if (callback (data, start, auxmap_start, flags))
- break;
- if (auxmap_end - 1 < end - 1)
- if (callback (data, auxmap_end, end, flags))
- break;
- }
- else
- {
- if (callback (data, start, end, flags))
- break;
- }
- }
- rof_close (&rof);
+ return vma_iterate_proc (callback, data);
+# else
+ /* On the other platforms, try the /proc approach first, and the sysctl()
+ as a fallback. */
+ int retval = vma_iterate_proc (callback, data);
+ if (retval == 0)
return 0;
- }
- /* Fallback if /proc is not accessible: Use sysctl(). */
return vma_iterate_bsd (callback, data);
+# endif
#elif defined __sgi || defined __osf__ /* IRIX, OSF/1 */