2009-06-05 Tristan Gingold <gingold@adacore.com>
[deliverable/binutils-gdb.git] / bfd / bfdwin.c
CommitLineData
93509525 1/* Support for memory-mapped windows into a BFD.
515ef31d 2 Copyright 1995, 1996, 2001, 2002, 2003, 2005, 2007, 2008
182a0099 3 Free Software Foundation, Inc.
93509525
KD
4 Written by Cygnus Support.
5
cd123cb7 6 This file is part of BFD, the Binary File Descriptor library.
93509525 7
cd123cb7
NC
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
93509525 12
cd123cb7
NC
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
93509525 17
cd123cb7
NC
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
93509525
KD
22
23#include "sysdep.h"
24
25#include "bfd.h"
26#include "libbfd.h"
27
78bc95e3
TG
28/* Currently, if USE_MMAP is undefined, none of the window stuff is
29 used. Enabled by --with-mmap. */
93509525
KD
30
31#ifdef USE_MMAP
32
33#undef HAVE_MPROTECT /* code's not tested yet */
34
35#if HAVE_MMAP || HAVE_MPROTECT || HAVE_MADVISE
36#include <sys/mman.h>
37#endif
38
39#ifndef MAP_FILE
40#define MAP_FILE 0
41#endif
42
43static int debug_windows;
44
45/* The idea behind the next and refcount fields is that one mapped
46 region can suffice for multiple read-only windows or multiple
47 non-overlapping read-write windows. It's not implemented yet
48 though. */
49
50/*
51INTERNAL_DEFINITION
52
53.struct _bfd_window_internal {
54. struct _bfd_window_internal *next;
c58b9523 55. void *data;
93509525
KD
56. bfd_size_type size;
57. int refcount : 31; {* should be enough... *}
58. unsigned mapped : 1; {* 1 = mmap, 0 = malloc *}
59.};
60*/
61
62void
c58b9523 63bfd_init_window (bfd_window *windowp)
93509525
KD
64{
65 windowp->data = 0;
66 windowp->i = 0;
67 windowp->size = 0;
68}
69
70void
c58b9523 71bfd_free_window (bfd_window *windowp)
93509525
KD
72{
73 bfd_window_internal *i = windowp->i;
74 windowp->i = 0;
75 windowp->data = 0;
76 if (i == 0)
77 return;
78 i->refcount--;
79 if (debug_windows)
80 fprintf (stderr, "freeing window @%p<%p,%lx,%p>\n",
81 windowp, windowp->data, windowp->size, windowp->i);
82 if (i->refcount != 0)
83 return;
84
85 if (i->mapped)
86 {
87#ifdef HAVE_MMAP
88 munmap (i->data, i->size);
89 goto no_free;
90#else
91 abort ();
92#endif
93 }
94#ifdef HAVE_MPROTECT
95 mprotect (i->data, i->size, PROT_READ | PROT_WRITE);
96#endif
97 free (i->data);
98#ifdef HAVE_MMAP
99 no_free:
100#endif
101 i->data = 0;
102 /* There should be no more references to i at this point. */
103 free (i);
104}
105
106static int ok_to_map = 1;
107
b34976b6 108bfd_boolean
c58b9523
AM
109bfd_get_file_window (bfd *abfd,
110 file_ptr offset,
111 bfd_size_type size,
112 bfd_window *windowp,
113 bfd_boolean writable)
93509525
KD
114{
115 static size_t pagesize;
116 bfd_window_internal *i = windowp->i;
117 bfd_size_type size_to_alloc = size;
118
119 if (debug_windows)
120 fprintf (stderr, "bfd_get_file_window (%p, %6ld, %6ld, %p<%p,%lx,%p>, %d)",
121 abfd, (long) offset, (long) size,
122 windowp, windowp->data, (unsigned long) windowp->size,
123 windowp->i, writable);
124
125 /* Make sure we know the page size, so we can be friendly to mmap. */
126 if (pagesize == 0)
127 pagesize = getpagesize ();
128 if (pagesize == 0)
129 abort ();
130
131 if (i == 0)
132 {
c58b9523 133 i = bfd_zmalloc (sizeof (bfd_window_internal));
93509525
KD
134 windowp->i = i;
135 if (i == 0)
b34976b6 136 return FALSE;
93509525
KD
137 i->data = 0;
138 }
139#ifdef HAVE_MMAP
140 if (ok_to_map
141 && (i->data == 0 || i->mapped == 1)
142 && (abfd->flags & BFD_IN_MEMORY) == 0)
143 {
144 file_ptr file_offset, offset2;
145 size_t real_size;
146 int fd;
93509525
KD
147
148 /* Find the real file and the real offset into it. */
149 while (abfd->my_archive != NULL)
150 {
151 offset += abfd->origin;
152 abfd = abfd->my_archive;
153 }
182a0099
AM
154
155 /* Seek into the file, to ensure it is open if cacheable. */
156 if (abfd->iostream == NULL
157 && (abfd->iovec == NULL
158 || abfd->iovec->bseek (abfd, offset, SEEK_SET) != 0))
3dff57e8 159 return FALSE;
182a0099 160 fd = fileno ((FILE *) abfd->iostream);
93509525
KD
161
162 /* Compute offsets and size for mmap and for the user's data. */
163 offset2 = offset % pagesize;
164 if (offset2 < 0)
165 abort ();
166 file_offset = offset - offset2;
167 real_size = offset + size - file_offset;
168 real_size = real_size + pagesize - 1;
169 real_size -= real_size % pagesize;
170
171 /* If we're re-using a memory region, make sure it's big enough. */
172 if (i->data && i->size < size)
173 {
174 munmap (i->data, i->size);
175 i->data = 0;
176 }
177 i->data = mmap (i->data, real_size,
178 writable ? PROT_WRITE | PROT_READ : PROT_READ,
179 (writable
180 ? MAP_FILE | MAP_PRIVATE
181 : MAP_FILE | MAP_SHARED),
182 fd, file_offset);
c58b9523 183 if (i->data == (void *) -1)
93509525
KD
184 {
185 /* An error happened. Report it, or try using malloc, or
186 something. */
187 bfd_set_error (bfd_error_system_call);
188 i->data = 0;
189 windowp->data = 0;
190 if (debug_windows)
191 fprintf (stderr, "\t\tmmap failed!\n");
b34976b6 192 return FALSE;
93509525
KD
193 }
194 if (debug_windows)
195 fprintf (stderr, "\n\tmapped %ld at %p, offset is %ld\n",
196 (long) real_size, i->data, (long) offset2);
197 i->size = real_size;
c58b9523 198 windowp->data = (bfd_byte *) i->data + offset2;
93509525
KD
199 windowp->size = size;
200 i->mapped = 1;
b34976b6 201 return TRUE;
93509525
KD
202 }
203 else if (debug_windows)
204 {
205 if (ok_to_map)
206 fprintf (stderr, _("not mapping: data=%lx mapped=%d\n"),
207 (unsigned long) i->data, (int) i->mapped);
208 else
209 fprintf (stderr, _("not mapping: env var not set\n"));
210 }
211#else
212 ok_to_map = 0;
213#endif
214
215#ifdef HAVE_MPROTECT
216 if (!writable)
217 {
218 size_to_alloc += pagesize - 1;
219 size_to_alloc -= size_to_alloc % pagesize;
220 }
221#endif
222 if (debug_windows)
223 fprintf (stderr, "\n\t%s(%6ld)",
224 i->data ? "realloc" : " malloc", (long) size_to_alloc);
515ef31d 225 i->data = bfd_realloc_or_free (i->data, size_to_alloc);
93509525
KD
226 if (debug_windows)
227 fprintf (stderr, "\t-> %p\n", i->data);
93509525
KD
228 if (i->data == NULL)
229 {
230 if (size_to_alloc == 0)
b34976b6
AM
231 return TRUE;
232 return FALSE;
93509525 233 }
515ef31d 234 i->refcount = 1;
93509525 235 if (bfd_seek (abfd, offset, SEEK_SET) != 0)
b34976b6 236 return FALSE;
93509525
KD
237 i->size = bfd_bread (i->data, size, abfd);
238 if (i->size != size)
b34976b6 239 return FALSE;
93509525
KD
240 i->mapped = 0;
241#ifdef HAVE_MPROTECT
242 if (!writable)
243 {
244 if (debug_windows)
245 fprintf (stderr, "\tmprotect (%p, %ld, PROT_READ)\n", i->data,
246 (long) i->size);
247 mprotect (i->data, i->size, PROT_READ);
248 }
249#endif
250 windowp->data = i->data;
251 windowp->size = i->size;
b34976b6 252 return TRUE;
93509525
KD
253}
254
255#endif /* USE_MMAP */
This page took 0.45135 seconds and 4 git commands to generate.