Mercurial > hg > octave-shane > gnulib-hg
annotate lib/vma-iter.c @ 17480:f40b3156a43e
selinux-at: omit unnecessary include
* lib/selinux-at.c: Don't include dosname.h; not needed, since
this source file doesn't use its macros, and subsidiary files that
use the macros already include it.
author | Paul Eggert <eggert@cs.ucla.edu> |
---|---|
date | Fri, 23 Aug 2013 13:53:46 -0700 |
parents | e542fd46ad6f |
children | 344018b6e5d7 |
rev | line source |
---|---|
14220 | 1 /* Iteration over virtual memory areas. |
17249
e542fd46ad6f
maint: update all copyright year number ranges
Eric Blake <eblake@redhat.com>
parents:
16935
diff
changeset
|
2 Copyright (C) 2011-2013 Free Software Foundation, Inc. |
14220 | 3 Written by Bruno Haible <bruno@clisp.org>, 2011. |
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 <http://www.gnu.org/licenses/>. */ | |
17 | |
18 #include <config.h> | |
19 | |
20 /* Specification. */ | |
21 #include "vma-iter.h" | |
22 | |
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 */ | |
27 | |
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 */ | |
33 #endif | |
34 | |
16935
498a2211d839
Write "Mac OS X" instead of "MacOS X".
Bruno Haible <bruno@clisp.org>
parents:
16201
diff
changeset
|
35 #if defined __APPLE__ && defined __MACH__ /* Mac OS X */ |
14220 | 36 # include <mach/mach.h> |
37 #endif | |
38 | |
39 #if (defined _WIN32 || defined __WIN32__) || defined __CYGWIN__ /* Windows */ | |
40 # include <windows.h> | |
41 #endif | |
42 | |
14226
7e521272b3c6
vma-iter: Treat Haiku like BeOS.
Bruno Haible <bruno@clisp.org>
parents:
14223
diff
changeset
|
43 #if defined __BEOS__ || defined __HAIKU__ /* BeOS, Haiku */ |
14220 | 44 # include <OS.h> |
45 #endif | |
46 | |
14235
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
47 #if HAVE_MQUERY /* OpenBSD */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
48 # include <sys/types.h> |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
49 # include <sys/mman.h> /* mquery */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
50 #endif |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
51 |
14220 | 52 |
53 /* Support for reading text files in the /proc file system. */ | |
54 | |
55 #if defined __linux__ || defined __FreeBSD__ || defined __NetBSD__ /* || defined __CYGWIN__ */ | |
56 | |
57 /* Buffered read-only streams. | |
58 We cannot use <stdio.h> here, because fopen() calls malloc(), and a malloc() | |
59 call may call mmap() and thus pre-allocate available memory. */ | |
60 | |
61 struct rofile | |
62 { | |
63 int fd; | |
64 size_t position; | |
65 size_t filled; | |
66 int eof_seen; | |
67 char buffer[1024]; | |
68 }; | |
69 | |
70 /* Open a read-only file stream. */ | |
71 static int | |
72 rof_open (struct rofile *rof, const char *filename) | |
73 { | |
74 int fd = open (filename, O_RDONLY); | |
75 if (fd < 0) | |
76 return -1; | |
77 rof->fd = fd; | |
78 rof->position = 0; | |
79 rof->filled = 0; | |
80 rof->eof_seen = 0; | |
81 return 0; | |
82 } | |
83 | |
84 /* Return the next byte from a read-only file stream without consuming it, | |
85 or -1 at EOF. */ | |
86 static int | |
87 rof_peekchar (struct rofile *rof) | |
88 { | |
89 if (rof->position == rof->filled) | |
90 { | |
91 if (rof->eof_seen) | |
92 return -1; | |
93 else | |
94 for (;;) | |
95 { | |
96 int n = read (rof->fd, rof->buffer, sizeof (rof->buffer)); | |
97 # ifdef EINTR | |
98 if (n < 0 && errno == EINTR) | |
99 continue; | |
100 # endif | |
101 if (n <= 0) | |
102 { | |
103 rof->eof_seen = 1; | |
104 return -1; | |
105 } | |
106 rof->filled = n; | |
107 rof->position = 0; | |
108 break; | |
109 } | |
110 } | |
111 return (unsigned char) rof->buffer[rof->position]; | |
112 } | |
113 | |
114 /* Return the next byte from a read-only file stream, or -1 at EOF. */ | |
115 static int | |
116 rof_getchar (struct rofile *rof) | |
117 { | |
118 int c = rof_peekchar (rof); | |
119 if (c >= 0) | |
120 rof->position++; | |
121 return c; | |
122 } | |
123 | |
124 /* Parse an unsigned hexadecimal number from a read-only file stream. */ | |
125 static int | |
126 rof_scanf_lx (struct rofile *rof, unsigned long *valuep) | |
127 { | |
128 unsigned long value = 0; | |
129 unsigned int numdigits = 0; | |
130 for (;;) | |
131 { | |
132 int c = rof_peekchar (rof); | |
133 if (c >= '0' && c <= '9') | |
134 value = (value << 4) + (c - '0'); | |
135 else if (c >= 'A' && c <= 'F') | |
136 value = (value << 4) + (c - 'A' + 10); | |
137 else if (c >= 'a' && c <= 'f') | |
138 value = (value << 4) + (c - 'a' + 10); | |
139 else | |
140 break; | |
141 rof_getchar (rof); | |
142 numdigits++; | |
143 } | |
144 if (numdigits == 0) | |
145 return -1; | |
146 *valuep = value; | |
147 return 0; | |
148 } | |
149 | |
150 /* Close a read-only file stream. */ | |
151 static void | |
152 rof_close (struct rofile *rof) | |
153 { | |
154 close (rof->fd); | |
155 } | |
156 | |
157 #endif | |
158 | |
159 | |
160 void | |
161 vma_iterate (vma_iterate_callback_fn callback, void *data) | |
162 { | |
163 #if defined __linux__ /* || defined __CYGWIN__ */ | |
164 | |
165 struct rofile rof; | |
166 int c; | |
167 | |
168 /* Open the current process' maps file. It describes one VMA per line. */ | |
169 if (rof_open (&rof, "/proc/self/maps") < 0) | |
170 return; | |
171 | |
172 for (;;) | |
173 { | |
174 unsigned long start, end; | |
175 unsigned int flags; | |
176 | |
177 /* Parse one line. First start and end. */ | |
178 if (!(rof_scanf_lx (&rof, &start) >= 0 | |
179 && rof_getchar (&rof) == '-' | |
180 && rof_scanf_lx (&rof, &end) >= 0)) | |
181 break; | |
182 /* Then the flags. */ | |
183 do | |
184 c = rof_getchar (&rof); | |
185 while (c == ' '); | |
186 flags = 0; | |
187 if (c == 'r') | |
188 flags |= VMA_PROT_READ; | |
189 c = rof_getchar (&rof); | |
190 if (c == 'w') | |
191 flags |= VMA_PROT_WRITE; | |
192 c = rof_getchar (&rof); | |
193 if (c == 'x') | |
194 flags |= VMA_PROT_EXECUTE; | |
195 while (c = rof_getchar (&rof), c != -1 && c != '\n') | |
196 ; | |
197 | |
198 if (callback (data, start, end, flags)) | |
199 break; | |
200 } | |
201 rof_close (&rof); | |
202 | |
203 #elif defined __FreeBSD__ || defined __NetBSD__ | |
204 | |
205 struct rofile rof; | |
206 int c; | |
207 | |
208 /* Open the current process' maps file. It describes one VMA per line. */ | |
209 if (rof_open (&rof, "/proc/curproc/map") < 0) | |
210 return; | |
211 | |
212 for (;;) | |
213 { | |
214 unsigned long start, end; | |
215 unsigned int flags; | |
216 | |
217 /* Parse one line. First start. */ | |
218 if (!(rof_getchar (&rof) == '0' | |
219 && rof_getchar (&rof) == 'x' | |
220 && rof_scanf_lx (&rof, &start) >= 0)) | |
221 break; | |
222 while (c = rof_peekchar (&rof), c == ' ' || c == '\t') | |
223 rof_getchar (&rof); | |
224 /* Then end. */ | |
225 if (!(rof_getchar (&rof) == '0' | |
226 && rof_getchar (&rof) == 'x' | |
227 && rof_scanf_lx (&rof, &end) >= 0)) | |
228 break; | |
229 /* Then the flags. */ | |
230 do | |
231 c = rof_getchar (&rof); | |
232 while (c == ' '); | |
233 flags = 0; | |
234 if (c == 'r') | |
235 flags |= VMA_PROT_READ; | |
236 c = rof_getchar (&rof); | |
237 if (c == 'w') | |
238 flags |= VMA_PROT_WRITE; | |
239 c = rof_getchar (&rof); | |
240 if (c == 'x') | |
241 flags |= VMA_PROT_EXECUTE; | |
242 while (c = rof_getchar (&rof), c != -1 && c != '\n') | |
243 ; | |
244 | |
245 if (callback (data, start, end, flags)) | |
246 break; | |
247 } | |
248 rof_close (&rof); | |
249 | |
250 #elif defined __sgi || defined __osf__ /* IRIX, OSF/1 */ | |
251 | |
252 size_t pagesize; | |
253 char fnamebuf[6+10+1]; | |
254 char *fname; | |
255 int fd; | |
256 int nmaps; | |
257 size_t memneed; | |
258 # if HAVE_MAP_ANONYMOUS | |
259 # define zero_fd -1 | |
260 # define map_flags MAP_ANONYMOUS | |
261 # else | |
262 int zero_fd; | |
263 # define map_flags 0 | |
264 # endif | |
265 void *auxmap; | |
266 unsigned long auxmap_start; | |
267 unsigned long auxmap_end; | |
268 prmap_t* maps; | |
269 prmap_t* mp; | |
270 | |
271 pagesize = getpagesize (); | |
272 | |
273 /* Construct fname = sprintf (fnamebuf+i, "/proc/%u", getpid ()). */ | |
274 fname = fnamebuf + sizeof (fnamebuf) - 1; | |
275 *fname = '\0'; | |
276 { | |
277 unsigned int value = getpid (); | |
278 do | |
279 *--fname = (value % 10) + '0'; | |
280 while ((value = value / 10) > 0); | |
281 } | |
282 fname -= 6; | |
283 memcpy (fname, "/proc/", 6); | |
284 | |
285 fd = open (fname, O_RDONLY); | |
286 if (fd < 0) | |
287 return; | |
288 | |
289 if (ioctl (fd, PIOCNMAP, &nmaps) < 0) | |
290 goto fail2; | |
291 | |
292 memneed = (nmaps + 10) * sizeof (prmap_t); | |
293 /* Allocate memneed bytes of memory. | |
294 We cannot use alloca here, because not much stack space is guaranteed. | |
295 We also cannot use malloc here, because a malloc() call may call mmap() | |
296 and thus pre-allocate available memory. | |
297 So use mmap(), and ignore the resulting VMA. */ | |
298 memneed = ((memneed - 1) / pagesize + 1) * pagesize; | |
299 # if !HAVE_MAP_ANONYMOUS | |
300 zero_fd = open ("/dev/zero", O_RDONLY, 0644); | |
301 if (zero_fd < 0) | |
302 goto fail2; | |
303 # endif | |
304 auxmap = (void *) mmap ((void *) 0, memneed, PROT_READ | PROT_WRITE, | |
305 map_flags | MAP_PRIVATE, zero_fd, 0); | |
306 # if !HAVE_MAP_ANONYMOUS | |
307 close (zero_fd); | |
308 # endif | |
309 if (auxmap == (void *) -1) | |
310 goto fail2; | |
311 auxmap_start = (unsigned long) auxmap; | |
312 auxmap_end = auxmap_start + memneed; | |
313 maps = (prmap_t *) auxmap; | |
314 | |
315 if (ioctl (fd, PIOCMAP, maps) < 0) | |
316 goto fail1; | |
317 | |
318 for (mp = maps;;) | |
319 { | |
320 unsigned long start, end; | |
321 unsigned int flags; | |
322 | |
323 start = (unsigned long) mp->pr_vaddr; | |
324 end = start + mp->pr_size; | |
325 if (start == 0 && end == 0) | |
326 break; | |
327 flags = 0; | |
328 if (mp->pr_mflags & MA_READ) | |
329 flags |= VMA_PROT_READ; | |
330 if (mp->pr_mflags & MA_WRITE) | |
331 flags |= VMA_PROT_WRITE; | |
332 if (mp->pr_mflags & MA_EXEC) | |
333 flags |= VMA_PROT_EXECUTE; | |
334 mp++; | |
335 if (start <= auxmap_start && auxmap_end - 1 <= end - 1) | |
336 { | |
337 /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1] | |
338 = [start,auxmap_start-1] u [auxmap_end,end-1]. */ | |
14223
af4da95a33d1
vma-iter: Avoid empty intervals.
Bruno Haible <bruno@clisp.org>
parents:
14220
diff
changeset
|
339 if (start < auxmap_start) |
af4da95a33d1
vma-iter: Avoid empty intervals.
Bruno Haible <bruno@clisp.org>
parents:
14220
diff
changeset
|
340 if (callback (data, start, auxmap_start, flags)) |
af4da95a33d1
vma-iter: Avoid empty intervals.
Bruno Haible <bruno@clisp.org>
parents:
14220
diff
changeset
|
341 break; |
af4da95a33d1
vma-iter: Avoid empty intervals.
Bruno Haible <bruno@clisp.org>
parents:
14220
diff
changeset
|
342 if (auxmap_end - 1 < end - 1) |
af4da95a33d1
vma-iter: Avoid empty intervals.
Bruno Haible <bruno@clisp.org>
parents:
14220
diff
changeset
|
343 if (callback (data, auxmap_end, end, flags)) |
af4da95a33d1
vma-iter: Avoid empty intervals.
Bruno Haible <bruno@clisp.org>
parents:
14220
diff
changeset
|
344 break; |
14220 | 345 } |
346 else | |
347 { | |
348 if (callback (data, start, end, flags)) | |
349 break; | |
350 } | |
351 } | |
352 munmap (auxmap, memneed); | |
353 close (fd); | |
354 return; | |
355 | |
356 fail1: | |
357 munmap (auxmap, memneed); | |
358 fail2: | |
359 close (fd); | |
360 return; | |
361 | |
16935
498a2211d839
Write "Mac OS X" instead of "MacOS X".
Bruno Haible <bruno@clisp.org>
parents:
16201
diff
changeset
|
362 #elif defined __APPLE__ && defined __MACH__ /* Mac OS X */ |
14220 | 363 |
364 task_t task = mach_task_self (); | |
365 vm_address_t address; | |
366 vm_size_t size; | |
367 | |
368 for (address = VM_MIN_ADDRESS;; address += size) | |
369 { | |
370 int more; | |
371 mach_port_t object_name; | |
372 unsigned int flags; | |
16935
498a2211d839
Write "Mac OS X" instead of "MacOS X".
Bruno Haible <bruno@clisp.org>
parents:
16201
diff
changeset
|
373 /* In Mac OS X 10.5, the types vm_address_t, vm_offset_t, vm_size_t have |
14220 | 374 32 bits in 32-bit processes and 64 bits in 64-bit processes. Whereas |
375 mach_vm_address_t and mach_vm_size_t are always 64 bits large. | |
16935
498a2211d839
Write "Mac OS X" instead of "MacOS X".
Bruno Haible <bruno@clisp.org>
parents:
16201
diff
changeset
|
376 Mac OS X 10.5 has three vm_region like methods: |
14220 | 377 - vm_region. It has arguments that depend on whether the current |
378 process is 32-bit or 64-bit. When linking dynamically, this | |
379 function exists only in 32-bit processes. Therefore we use it only | |
380 in 32-bit processes. | |
381 - vm_region_64. It has arguments that depend on whether the current | |
382 process is 32-bit or 64-bit. It interprets a flavor | |
383 VM_REGION_BASIC_INFO as VM_REGION_BASIC_INFO_64, which is | |
384 dangerous since 'struct vm_region_basic_info_64' is larger than | |
385 'struct vm_region_basic_info'; therefore let's write | |
386 VM_REGION_BASIC_INFO_64 explicitly. | |
387 - mach_vm_region. It has arguments that are 64-bit always. This | |
388 function is useful when you want to access the VM of a process | |
389 other than the current process. | |
390 In 64-bit processes, we could use vm_region_64 or mach_vm_region. | |
391 I choose vm_region_64 because it uses the same types as vm_region, | |
392 resulting in less conditional code. */ | |
393 # if defined __ppc64__ || defined __x86_64__ | |
394 struct vm_region_basic_info_64 info; | |
395 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64; | |
396 | |
397 more = (vm_region_64 (task, &address, &size, VM_REGION_BASIC_INFO_64, | |
398 (vm_region_info_t)&info, &info_count, &object_name) | |
399 == KERN_SUCCESS); | |
400 # else | |
401 struct vm_region_basic_info info; | |
402 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT; | |
403 | |
404 more = (vm_region (task, &address, &size, VM_REGION_BASIC_INFO, | |
405 (vm_region_info_t)&info, &info_count, &object_name) | |
406 == KERN_SUCCESS); | |
407 # endif | |
408 if (object_name != MACH_PORT_NULL) | |
409 mach_port_deallocate (mach_task_self (), object_name); | |
410 if (!more) | |
411 break; | |
412 flags = 0; | |
413 if (info.protection & VM_PROT_READ) | |
414 flags |= VMA_PROT_READ; | |
415 if (info.protection & VM_PROT_WRITE) | |
416 flags |= VMA_PROT_WRITE; | |
417 if (info.protection & VM_PROT_EXECUTE) | |
418 flags |= VMA_PROT_EXECUTE; | |
419 if (callback (data, address, address + size, flags)) | |
420 break; | |
421 } | |
422 | |
423 #elif (defined _WIN32 || defined __WIN32__) || defined __CYGWIN__ | |
424 /* Windows platform. Use the native Windows API. */ | |
425 | |
426 MEMORY_BASIC_INFORMATION info; | |
427 unsigned long address = 0; | |
428 | |
429 while (VirtualQuery ((void*)address, &info, sizeof(info)) == sizeof(info)) | |
430 { | |
431 if (info.State != MEM_FREE) | |
432 /* Ignore areas where info.State has the value MEM_RESERVE or, | |
433 equivalently, info.Protect has the undocumented value 0. | |
434 This is needed, so that on Cygwin, areas used by malloc() are | |
435 distinguished from areas reserved for future malloc(). */ | |
436 if (info.State != MEM_RESERVE) | |
437 { | |
438 unsigned long start, end; | |
439 unsigned int flags; | |
440 | |
441 start = (unsigned long)info.BaseAddress; | |
442 end = start + info.RegionSize; | |
443 switch (info.Protect & ~(PAGE_GUARD|PAGE_NOCACHE)) | |
444 { | |
445 case PAGE_READONLY: | |
446 flags = VMA_PROT_READ; | |
447 break; | |
448 case PAGE_READWRITE: | |
449 case PAGE_WRITECOPY: | |
450 flags = VMA_PROT_READ | VMA_PROT_WRITE; | |
451 break; | |
452 case PAGE_EXECUTE: | |
453 flags = VMA_PROT_EXECUTE; | |
454 break; | |
455 case PAGE_EXECUTE_READ: | |
456 flags = VMA_PROT_READ | VMA_PROT_EXECUTE; | |
457 break; | |
458 case PAGE_EXECUTE_READWRITE: | |
459 case PAGE_EXECUTE_WRITECOPY: | |
460 flags = VMA_PROT_READ | VMA_PROT_WRITE | VMA_PROT_EXECUTE; | |
461 break; | |
462 case PAGE_NOACCESS: | |
463 default: | |
464 flags = 0; | |
465 break; | |
466 } | |
467 | |
468 if (callback (data, start, end, flags)) | |
469 break; | |
470 } | |
471 address = (unsigned long)info.BaseAddress + info.RegionSize; | |
472 } | |
473 | |
14226
7e521272b3c6
vma-iter: Treat Haiku like BeOS.
Bruno Haible <bruno@clisp.org>
parents:
14223
diff
changeset
|
474 #elif defined __BEOS__ || defined __HAIKU__ |
14220 | 475 /* Use the BeOS specific API. */ |
476 | |
477 area_info info; | |
478 int32 cookie; | |
479 | |
480 cookie = 0; | |
481 while (get_next_area_info (0, &cookie, &info) == B_OK) | |
482 { | |
483 unsigned long start, end; | |
484 unsigned int flags; | |
485 | |
486 start = (unsigned long) info.address; | |
487 end = start + info.size; | |
488 flags = 0; | |
489 if (info.protection & B_READ_AREA) | |
490 flags |= VMA_PROT_READ | VMA_PROT_EXECUTE; | |
491 if (info.protection & B_WRITE_AREA) | |
492 flags |= VMA_PROT_WRITE; | |
493 | |
494 if (callback (data, start, end, flags)) | |
495 break; | |
496 } | |
497 | |
14235
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
498 #elif HAVE_MQUERY /* OpenBSD */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
499 |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
500 uintptr_t pagesize; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
501 uintptr_t address; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
502 int /*bool*/ address_known_mapped; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
503 |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
504 pagesize = getpagesize (); |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
505 /* Avoid calling mquery with a NULL first argument, because this argument |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
506 value has a specific meaning. We know the NULL page is unmapped. */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
507 address = pagesize; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
508 address_known_mapped = 0; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
509 for (;;) |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
510 { |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
511 /* Test whether the page at address is mapped. */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
512 if (address_known_mapped |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
513 || mquery ((void *) address, pagesize, 0, MAP_FIXED, -1, 0) |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
514 == (void *) -1) |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
515 { |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
516 /* The page at address is mapped. |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
517 This is the start of an interval. */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
518 uintptr_t start = address; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
519 uintptr_t end; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
520 |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
521 /* Find the end of the interval. */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
522 end = (uintptr_t) mquery ((void *) address, pagesize, 0, 0, -1, 0); |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
523 if (end == (uintptr_t) (void *) -1) |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
524 end = 0; /* wrap around */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
525 address = end; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
526 |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
527 /* It's too complicated to find out about the flags. Just pass 0. */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
528 if (callback (data, start, end, 0)) |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
529 break; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
530 |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
531 if (address < pagesize) /* wrap around? */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
532 break; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
533 } |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
534 /* Here we know that the page at address is unmapped. */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
535 { |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
536 uintptr_t query_size = pagesize; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
537 |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
538 address += pagesize; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
539 |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
540 /* Query larger and larger blocks, to get through the unmapped address |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
541 range with few mquery() calls. */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
542 for (;;) |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
543 { |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
544 if (2 * query_size > query_size) |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
545 query_size = 2 * query_size; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
546 if (address + query_size - 1 < query_size) /* wrap around? */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
547 { |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
548 address_known_mapped = 0; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
549 break; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
550 } |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
551 if (mquery ((void *) address, query_size, 0, MAP_FIXED, -1, 0) |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
552 == (void *) -1) |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
553 { |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
554 /* Not all the interval [address .. address + query_size - 1] |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
555 is unmapped. */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
556 address_known_mapped = (query_size == pagesize); |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
557 break; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
558 } |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
559 /* The interval [address .. address + query_size - 1] is |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
560 unmapped. */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
561 address += query_size; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
562 } |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
563 /* Reduce the query size again, to determine the precise size of the |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
564 unmapped interval that starts at address. */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
565 while (query_size > pagesize) |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
566 { |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
567 query_size = query_size / 2; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
568 if (address + query_size - 1 >= query_size) |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
569 { |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
570 if (mquery ((void *) address, query_size, 0, MAP_FIXED, -1, 0) |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
571 != (void *) -1) |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
572 { |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
573 /* The interval [address .. address + query_size - 1] is |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
574 unmapped. */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
575 address += query_size; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
576 address_known_mapped = 0; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
577 } |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
578 else |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
579 address_known_mapped = (query_size == pagesize); |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
580 } |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
581 } |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
582 /* Here again query_size = pagesize, and |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
583 either address + pagesize - 1 < pagesize, or |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
584 mquery ((void *) address, pagesize, 0, MAP_FIXED, -1, 0) fails. |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
585 So, the unmapped area ends at address. */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
586 } |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
587 if (address + pagesize - 1 < pagesize) /* wrap around? */ |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
588 break; |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
589 } |
6b8b94f919ce
vma-iter, get-rusage-as: Add OpenBSD support.
Bruno Haible <bruno@clisp.org>
parents:
14226
diff
changeset
|
590 |
14220 | 591 #endif |
592 } | |
593 | |
594 | |
595 #ifdef TEST | |
596 | |
597 #include <stdio.h> | |
598 | |
599 /* Output the VMAs of the current process in a format similar to the Linux | |
600 /proc/$pid/maps file. */ | |
601 | |
602 static int | |
603 vma_iterate_callback (void *data, uintptr_t start, uintptr_t end, | |
604 unsigned int flags) | |
605 { | |
606 printf ("%08lx-%08lx %c%c%c\n", | |
607 (unsigned long) start, (unsigned long) end, | |
608 flags & VMA_PROT_READ ? 'r' : '-', | |
609 flags & VMA_PROT_WRITE ? 'w' : '-', | |
610 flags & VMA_PROT_EXECUTE ? 'x' : '-'); | |
611 return 0; | |
612 } | |
613 | |
614 int | |
615 main () | |
616 { | |
617 vma_iterate (vma_iterate_callback, NULL); | |
618 | |
619 /* Let the user interactively look at the /proc file system. */ | |
620 sleep (10); | |
621 | |
622 return 0; | |
623 } | |
624 | |
625 #endif /* TEST */ |