Bump version number.
[libsigsegv/ericb.git] / src / stackvma-procfs.c
blobdba43a3b7340b741fe7a50baa6fbf650bb671bef
1 /* Determine the virtual memory area of a given address.
2 Copyright (C) 2002, 2006, 2008-2009 Bruno Haible <bruno@clisp.org>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 #include "stackvma.h"
19 #include <unistd.h> /* open, close */
20 #include <fcntl.h> /* open */
21 #include <string.h> /* memcpy */
22 #include <sys/types.h>
23 #include <sys/mman.h> /* mmap, munmap */
24 #include <sys/procfs.h> /* PIOC*, prmap_t */
26 #include "stackvma-simple.c"
28 #if HAVE_MINCORE
29 # define sigsegv_get_vma mincore_get_vma
30 # define STATIC static
31 # include "stackvma-mincore.c"
32 # undef sigsegv_get_vma
33 #else
34 /* Cache for getpagesize(). */
35 static unsigned long pagesize;
36 /* Initialize pagesize. */
37 static void
38 init_pagesize (void)
40 pagesize = getpagesize ();
42 #endif
44 int
45 sigsegv_get_vma (unsigned long address, struct vma_struct *vma)
47 char fnamebuf[6+10+1];
48 char *fname;
49 int fd;
50 int nmaps;
51 size_t memneed;
52 #if HAVE_MMAP_ANON
53 # define zero_fd -1
54 # define map_flags MAP_ANON
55 #elif HAVE_MMAP_ANONYMOUS
56 # define zero_fd -1
57 # define map_flags MAP_ANONYMOUS
58 #else
59 int zero_fd;
60 # define map_flags 0
61 #endif
62 void *auxmap;
63 unsigned long auxmap_start;
64 unsigned long auxmap_end;
65 prmap_t* maps;
66 prmap_t* mp;
67 unsigned long start, end;
68 #if STACK_DIRECTION < 0
69 unsigned long prev;
70 #endif
72 if (pagesize == 0)
73 init_pagesize ();
75 /* Construct fname = sprintf (fnamebuf+i, "/proc/%u", getpid ()). */
76 fname = fnamebuf + sizeof (fnamebuf) - 1;
77 *fname = '\0';
79 unsigned int value = getpid ();
81 *--fname = (value % 10) + '0';
82 while ((value = value / 10) > 0);
84 fname -= 6;
85 memcpy (fname, "/proc/", 6);
87 fd = open (fname, O_RDONLY);
88 if (fd < 0)
89 goto failed;
91 if (ioctl (fd, PIOCNMAP, &nmaps) < 0)
92 goto fail2;
94 memneed = (nmaps + 10) * sizeof (prmap_t);
95 /* Allocate memneed bytes of memory.
96 We cannot use alloca here, because we are low on stack space.
97 We also cannot use malloc here, because a malloc() call may have been
98 interrupted.
99 So use mmap(), and ignore the resulting VMA. */
100 memneed = ((memneed - 1) / pagesize + 1) * pagesize;
101 #if !(HAVE_MMAP_ANON || HAVE_MMAP_ANONYMOUS)
102 zero_fd = open ("/dev/zero", O_RDONLY, 0644);
103 if (zero_fd < 0)
104 goto fail2;
105 #endif
106 auxmap = (void *) mmap ((void *) 0, memneed, PROT_READ | PROT_WRITE, map_flags | MAP_PRIVATE, zero_fd, 0);
107 #if !(HAVE_MMAP_ANON || HAVE_MMAP_ANONYMOUS)
108 close (zero_fd);
109 #endif
110 if (auxmap == (void *) -1)
111 goto fail2;
112 auxmap_start = (unsigned long) auxmap;
113 auxmap_end = auxmap_start + memneed;
114 maps = (prmap_t *) auxmap;
116 if (ioctl (fd, PIOCMAP, maps) < 0)
117 goto fail1;
119 #if STACK_DIRECTION < 0
120 prev = 0;
121 #endif
122 for (mp = maps;;)
124 start = (unsigned long) mp->pr_vaddr;
125 end = start + mp->pr_size;
126 if (start == 0 && end == 0)
127 break;
128 mp++;
129 if (start <= auxmap_start && auxmap_end - 1 <= end - 1)
131 /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1]
132 = [start,auxmap_start-1] u [auxmap_end,end-1]. */
133 if (start != auxmap_start)
135 if (address >= start && address <= auxmap_start - 1)
137 end = auxmap_start;
138 goto found;
140 #if STACK_DIRECTION < 0
141 prev = auxmap_start;
142 #endif
144 if (end != auxmap_end)
146 if (address >= auxmap_end && address <= end - 1)
148 start = auxmap_end;
149 goto found;
151 #if STACK_DIRECTION < 0
152 prev = end;
153 #endif
156 else
158 if (address >= start && address <= end - 1)
159 goto found;
160 #if STACK_DIRECTION < 0
161 prev = end;
162 #endif
166 fail1:
167 munmap (auxmap, memneed);
168 fail2:
169 close (fd);
170 failed:
171 #if HAVE_MINCORE
172 return mincore_get_vma (address, vma);
173 #else
174 return -1;
175 #endif
177 found:
178 vma->start = start;
179 vma->end = end;
180 #if STACK_DIRECTION < 0
181 vma->prev_end = prev;
182 #else
183 vma->next_start = (unsigned long) mp->pr_vaddr;
184 #endif
185 munmap (auxmap, memneed);
186 close (fd);
187 vma->is_near_this = simple_is_near_this;
188 return 0;