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__ /* BeOS */
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 (callback (data, start, auxmap_start, flags))
336 if (callback (data, auxmap_end, end, flags))
341 if (callback (data, start, end, flags))
345 munmap (auxmap, memneed);
350 munmap (auxmap, memneed);
355 #elif defined __APPLE__ && defined __MACH__ /* MacOS X */
357 task_t task = mach_task_self ();
358 vm_address_t address;
361 for (address = VM_MIN_ADDRESS;; address += size)
364 mach_port_t object_name;
366 /* In MacOS X 10.5, the types vm_address_t, vm_offset_t, vm_size_t have
367 32 bits in 32-bit processes and 64 bits in 64-bit processes. Whereas
368 mach_vm_address_t and mach_vm_size_t are always 64 bits large.
369 MacOS X 10.5 has three vm_region like methods:
370 - vm_region. It has arguments that depend on whether the current
371 process is 32-bit or 64-bit. When linking dynamically, this
372 function exists only in 32-bit processes. Therefore we use it only
374 - vm_region_64. It has arguments that depend on whether the current
375 process is 32-bit or 64-bit. It interprets a flavor
376 VM_REGION_BASIC_INFO as VM_REGION_BASIC_INFO_64, which is
377 dangerous since 'struct vm_region_basic_info_64' is larger than
378 'struct vm_region_basic_info'; therefore let's write
379 VM_REGION_BASIC_INFO_64 explicitly.
380 - mach_vm_region. It has arguments that are 64-bit always. This
381 function is useful when you want to access the VM of a process
382 other than the current process.
383 In 64-bit processes, we could use vm_region_64 or mach_vm_region.
384 I choose vm_region_64 because it uses the same types as vm_region,
385 resulting in less conditional code. */
386 # if defined __ppc64__ || defined __x86_64__
387 struct vm_region_basic_info_64 info;
388 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
390 more = (vm_region_64 (task, &address, &size, VM_REGION_BASIC_INFO_64,
391 (vm_region_info_t)&info, &info_count, &object_name)
394 struct vm_region_basic_info info;
395 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
397 more = (vm_region (task, &address, &size, VM_REGION_BASIC_INFO,
398 (vm_region_info_t)&info, &info_count, &object_name)
401 if (object_name != MACH_PORT_NULL)
402 mach_port_deallocate (mach_task_self (), object_name);
406 if (info.protection & VM_PROT_READ)
407 flags |= VMA_PROT_READ;
408 if (info.protection & VM_PROT_WRITE)
409 flags |= VMA_PROT_WRITE;
410 if (info.protection & VM_PROT_EXECUTE)
411 flags |= VMA_PROT_EXECUTE;
412 if (callback (data, address, address + size, flags))
416 #elif (defined _WIN32 || defined __WIN32__) || defined __CYGWIN__
417 /* Windows platform. Use the native Windows API. */
419 MEMORY_BASIC_INFORMATION info;
420 unsigned long address = 0;
422 while (VirtualQuery ((void*)address, &info, sizeof(info)) == sizeof(info))
424 if (info.State != MEM_FREE)
425 /* Ignore areas where info.State has the value MEM_RESERVE or,
426 equivalently, info.Protect has the undocumented value 0.
427 This is needed, so that on Cygwin, areas used by malloc() are
428 distinguished from areas reserved for future malloc(). */
429 if (info.State != MEM_RESERVE)
431 unsigned long start, end;
434 start = (unsigned long)info.BaseAddress;
435 end = start + info.RegionSize;
436 switch (info.Protect & ~(PAGE_GUARD|PAGE_NOCACHE))
439 flags = VMA_PROT_READ;
443 flags = VMA_PROT_READ | VMA_PROT_WRITE;
446 flags = VMA_PROT_EXECUTE;
448 case PAGE_EXECUTE_READ:
449 flags = VMA_PROT_READ | VMA_PROT_EXECUTE;
451 case PAGE_EXECUTE_READWRITE:
452 case PAGE_EXECUTE_WRITECOPY:
453 flags = VMA_PROT_READ | VMA_PROT_WRITE | VMA_PROT_EXECUTE;
461 if (callback (data, start, end, flags))
464 address = (unsigned long)info.BaseAddress + info.RegionSize;
467 #elif defined __BEOS__
468 /* Use the BeOS specific API. */
474 while (get_next_area_info (0, &cookie, &info) == B_OK)
476 unsigned long start, end;
479 start = (unsigned long) info.address;
480 end = start + info.size;
482 if (info.protection & B_READ_AREA)
483 flags |= VMA_PROT_READ | VMA_PROT_EXECUTE;
484 if (info.protection & B_WRITE_AREA)
485 flags |= VMA_PROT_WRITE;
487 if (callback (data, start, end, flags))
499 /* Output the VMAs of the current process in a format similar to the Linux
500 /proc/$pid/maps file. */
503 vma_iterate_callback (void *data, uintptr_t start, uintptr_t end,
506 printf ("%08lx-%08lx %c%c%c\n",
507 (unsigned long) start, (unsigned long) end,
508 flags & VMA_PROT_READ ? 'r' : '-',
509 flags & VMA_PROT_WRITE ? 'w' : '-',
510 flags & VMA_PROT_EXECUTE ? 'x' : '-');
517 vma_iterate (vma_iterate_callback, NULL);
519 /* Let the user interactively look at the /proc file system. */