1 /* Iteration over virtual memory areas.
2 Copyright (C) 2011 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2011.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
23 #include <errno.h> /* errno */
24 #include <stdlib.h> /* size_t */
25 #include <fcntl.h> /* open, O_RDONLY */
26 #include <unistd.h> /* getpagesize, read, close */
28 #if defined __sgi || defined __osf__ /* IRIX, OSF/1 */
29 # include <string.h> /* memcpy */
30 # include <sys/types.h>
31 # include <sys/mman.h> /* mmap, munmap */
32 # include <sys/procfs.h> /* PIOC*, prmap_t */
35 #if defined __APPLE__ && defined __MACH__ /* MacOS X */
36 # include <mach/mach.h>
39 #if (defined _WIN32 || defined __WIN32__) || defined __CYGWIN__ /* Windows */
43 #if defined __BEOS__ || defined __HAIKU__ /* BeOS, Haiku */
48 /* Support for reading text files in the /proc file system. */
50 #if defined __linux__ || defined __FreeBSD__ || defined __NetBSD__ /* || defined __CYGWIN__ */
52 /* Buffered read-only streams.
53 We cannot use <stdio.h> here, because fopen() calls malloc(), and a malloc()
54 call may call mmap() and thus pre-allocate available memory. */
65 /* Open a read-only file stream. */
67 rof_open (struct rofile *rof, const char *filename)
69 int fd = open (filename, O_RDONLY);
79 /* Return the next byte from a read-only file stream without consuming it,
82 rof_peekchar (struct rofile *rof)
84 if (rof->position == rof->filled)
91 int n = read (rof->fd, rof->buffer, sizeof (rof->buffer));
93 if (n < 0 && errno == EINTR)
106 return (unsigned char) rof->buffer[rof->position];
109 /* Return the next byte from a read-only file stream, or -1 at EOF. */
111 rof_getchar (struct rofile *rof)
113 int c = rof_peekchar (rof);
119 /* Parse an unsigned hexadecimal number from a read-only file stream. */
121 rof_scanf_lx (struct rofile *rof, unsigned long *valuep)
123 unsigned long value = 0;
124 unsigned int numdigits = 0;
127 int c = rof_peekchar (rof);
128 if (c >= '0' && c <= '9')
129 value = (value << 4) + (c - '0');
130 else if (c >= 'A' && c <= 'F')
131 value = (value << 4) + (c - 'A' + 10);
132 else if (c >= 'a' && c <= 'f')
133 value = (value << 4) + (c - 'a' + 10);
145 /* Close a read-only file stream. */
147 rof_close (struct rofile *rof)
156 vma_iterate (vma_iterate_callback_fn callback, void *data)
158 #if defined __linux__ /* || defined __CYGWIN__ */
163 /* Open the current process' maps file. It describes one VMA per line. */
164 if (rof_open (&rof, "/proc/self/maps") < 0)
169 unsigned long start, end;
172 /* Parse one line. First start and end. */
173 if (!(rof_scanf_lx (&rof, &start) >= 0
174 && rof_getchar (&rof) == '-'
175 && rof_scanf_lx (&rof, &end) >= 0))
177 /* Then the flags. */
179 c = rof_getchar (&rof);
183 flags |= VMA_PROT_READ;
184 c = rof_getchar (&rof);
186 flags |= VMA_PROT_WRITE;
187 c = rof_getchar (&rof);
189 flags |= VMA_PROT_EXECUTE;
190 while (c = rof_getchar (&rof), c != -1 && c != '\n')
193 if (callback (data, start, end, flags))
198 #elif defined __FreeBSD__ || defined __NetBSD__
203 /* Open the current process' maps file. It describes one VMA per line. */
204 if (rof_open (&rof, "/proc/curproc/map") < 0)
209 unsigned long start, end;
212 /* Parse one line. First start. */
213 if (!(rof_getchar (&rof) == '0'
214 && rof_getchar (&rof) == 'x'
215 && rof_scanf_lx (&rof, &start) >= 0))
217 while (c = rof_peekchar (&rof), c == ' ' || c == '\t')
220 if (!(rof_getchar (&rof) == '0'
221 && rof_getchar (&rof) == 'x'
222 && rof_scanf_lx (&rof, &end) >= 0))
224 /* Then the flags. */
226 c = rof_getchar (&rof);
230 flags |= VMA_PROT_READ;
231 c = rof_getchar (&rof);
233 flags |= VMA_PROT_WRITE;
234 c = rof_getchar (&rof);
236 flags |= VMA_PROT_EXECUTE;
237 while (c = rof_getchar (&rof), c != -1 && c != '\n')
240 if (callback (data, start, end, flags))
245 #elif defined __sgi || defined __osf__ /* IRIX, OSF/1 */
248 char fnamebuf[6+10+1];
253 # if HAVE_MAP_ANONYMOUS
255 # define map_flags MAP_ANONYMOUS
261 unsigned long auxmap_start;
262 unsigned long auxmap_end;
266 pagesize = getpagesize ();
268 /* Construct fname = sprintf (fnamebuf+i, "/proc/%u", getpid ()). */
269 fname = fnamebuf + sizeof (fnamebuf) - 1;
272 unsigned int value = getpid ();
274 *--fname = (value % 10) + '0';
275 while ((value = value / 10) > 0);
278 memcpy (fname, "/proc/", 6);
280 fd = open (fname, O_RDONLY);
284 if (ioctl (fd, PIOCNMAP, &nmaps) < 0)
287 memneed = (nmaps + 10) * sizeof (prmap_t);
288 /* Allocate memneed bytes of memory.
289 We cannot use alloca here, because not much stack space is guaranteed.
290 We also cannot use malloc here, because a malloc() call may call mmap()
291 and thus pre-allocate available memory.
292 So use mmap(), and ignore the resulting VMA. */
293 memneed = ((memneed - 1) / pagesize + 1) * pagesize;
294 # if !HAVE_MAP_ANONYMOUS
295 zero_fd = open ("/dev/zero", O_RDONLY, 0644);
299 auxmap = (void *) mmap ((void *) 0, memneed, PROT_READ | PROT_WRITE,
300 map_flags | MAP_PRIVATE, zero_fd, 0);
301 # if !HAVE_MAP_ANONYMOUS
304 if (auxmap == (void *) -1)
306 auxmap_start = (unsigned long) auxmap;
307 auxmap_end = auxmap_start + memneed;
308 maps = (prmap_t *) auxmap;
310 if (ioctl (fd, PIOCMAP, maps) < 0)
315 unsigned long start, end;
318 start = (unsigned long) mp->pr_vaddr;
319 end = start + mp->pr_size;
320 if (start == 0 && end == 0)
323 if (mp->pr_mflags & MA_READ)
324 flags |= VMA_PROT_READ;
325 if (mp->pr_mflags & MA_WRITE)
326 flags |= VMA_PROT_WRITE;
327 if (mp->pr_mflags & MA_EXEC)
328 flags |= VMA_PROT_EXECUTE;
330 if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
332 /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
333 = [start,auxmap_start-1] u [auxmap_end,end-1]. */
334 if (start < auxmap_start)
335 if (callback (data, start, auxmap_start, flags))
337 if (auxmap_end - 1 < end - 1)
338 if (callback (data, auxmap_end, end, flags))
343 if (callback (data, start, end, flags))
347 munmap (auxmap, memneed);
352 munmap (auxmap, memneed);
357 #elif defined __APPLE__ && defined __MACH__ /* MacOS X */
359 task_t task = mach_task_self ();
360 vm_address_t address;
363 for (address = VM_MIN_ADDRESS;; address += size)
366 mach_port_t object_name;
368 /* In MacOS X 10.5, the types vm_address_t, vm_offset_t, vm_size_t have
369 32 bits in 32-bit processes and 64 bits in 64-bit processes. Whereas
370 mach_vm_address_t and mach_vm_size_t are always 64 bits large.
371 MacOS X 10.5 has three vm_region like methods:
372 - vm_region. It has arguments that depend on whether the current
373 process is 32-bit or 64-bit. When linking dynamically, this
374 function exists only in 32-bit processes. Therefore we use it only
376 - vm_region_64. It has arguments that depend on whether the current
377 process is 32-bit or 64-bit. It interprets a flavor
378 VM_REGION_BASIC_INFO as VM_REGION_BASIC_INFO_64, which is
379 dangerous since 'struct vm_region_basic_info_64' is larger than
380 'struct vm_region_basic_info'; therefore let's write
381 VM_REGION_BASIC_INFO_64 explicitly.
382 - mach_vm_region. It has arguments that are 64-bit always. This
383 function is useful when you want to access the VM of a process
384 other than the current process.
385 In 64-bit processes, we could use vm_region_64 or mach_vm_region.
386 I choose vm_region_64 because it uses the same types as vm_region,
387 resulting in less conditional code. */
388 # if defined __ppc64__ || defined __x86_64__
389 struct vm_region_basic_info_64 info;
390 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
392 more = (vm_region_64 (task, &address, &size, VM_REGION_BASIC_INFO_64,
393 (vm_region_info_t)&info, &info_count, &object_name)
396 struct vm_region_basic_info info;
397 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
399 more = (vm_region (task, &address, &size, VM_REGION_BASIC_INFO,
400 (vm_region_info_t)&info, &info_count, &object_name)
403 if (object_name != MACH_PORT_NULL)
404 mach_port_deallocate (mach_task_self (), object_name);
408 if (info.protection & VM_PROT_READ)
409 flags |= VMA_PROT_READ;
410 if (info.protection & VM_PROT_WRITE)
411 flags |= VMA_PROT_WRITE;
412 if (info.protection & VM_PROT_EXECUTE)
413 flags |= VMA_PROT_EXECUTE;
414 if (callback (data, address, address + size, flags))
418 #elif (defined _WIN32 || defined __WIN32__) || defined __CYGWIN__
419 /* Windows platform. Use the native Windows API. */
421 MEMORY_BASIC_INFORMATION info;
422 unsigned long address = 0;
424 while (VirtualQuery ((void*)address, &info, sizeof(info)) == sizeof(info))
426 if (info.State != MEM_FREE)
427 /* Ignore areas where info.State has the value MEM_RESERVE or,
428 equivalently, info.Protect has the undocumented value 0.
429 This is needed, so that on Cygwin, areas used by malloc() are
430 distinguished from areas reserved for future malloc(). */
431 if (info.State != MEM_RESERVE)
433 unsigned long start, end;
436 start = (unsigned long)info.BaseAddress;
437 end = start + info.RegionSize;
438 switch (info.Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
441 flags = VMA_PROT_READ;
445 flags = VMA_PROT_READ | VMA_PROT_WRITE;
448 flags = VMA_PROT_EXECUTE;
450 case PAGE_EXECUTE_READ:
451 flags = VMA_PROT_READ | VMA_PROT_EXECUTE;
453 case PAGE_EXECUTE_READWRITE:
454 case PAGE_EXECUTE_WRITECOPY:
455 flags = VMA_PROT_READ | VMA_PROT_WRITE | VMA_PROT_EXECUTE;
463 if (callback (data, start, end, flags))
466 address = (unsigned long)info.BaseAddress + info.RegionSize;
469 #elif defined __BEOS__ || defined __HAIKU__
470 /* Use the BeOS specific API. */
476 while (get_next_area_info (0, &cookie, &info) == B_OK)
478 unsigned long start, end;
481 start = (unsigned long) info.address;
482 end = start + info.size;
484 if (info.protection & B_READ_AREA)
485 flags |= VMA_PROT_READ | VMA_PROT_EXECUTE;
486 if (info.protection & B_WRITE_AREA)
487 flags |= VMA_PROT_WRITE;
489 if (callback (data, start, end, flags))
501 /* Output the VMAs of the current process in a format similar to the Linux
502 /proc/$pid/maps file. */
505 vma_iterate_callback (void *data, uintptr_t start, uintptr_t end,
508 printf ("%08lx-%08lx %c%c%c\n",
509 (unsigned long) start, (unsigned long) end,
510 flags & VMA_PROT_READ ? 'r' : '-',
511 flags & VMA_PROT_WRITE ? 'w' : '-',
512 flags & VMA_PROT_EXECUTE ? 'x' : '-');
519 vma_iterate (vma_iterate_callback, NULL);
521 /* Let the user interactively look at the /proc file system. */