*** empty log message ***
[deliverable/binutils-gdb.git] / bfd / bfdwin.c
CommitLineData
93509525 1/* Support for memory-mapped windows into a BFD.
103ae312 2 Copyright 1995, 1996, 2001, 2002, 2003, 2005, 2007, 2008, 2009, 2011
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",
848f5748 81 windowp, windowp->data, (unsigned long) windowp->size, windowp->i);
93509525
KD
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
103ae312 131 if (i == NULL)
93509525 132 {
c58b9523 133 i = bfd_zmalloc (sizeof (bfd_window_internal));
103ae312 134 if (i == NULL)
b34976b6 135 return FALSE;
103ae312 136 i->data = NULL;
93509525
KD
137 }
138#ifdef HAVE_MMAP
139 if (ok_to_map
103ae312 140 && (i->data == NULL || i->mapped == 1)
93509525
KD
141 && (abfd->flags & BFD_IN_MEMORY) == 0)
142 {
143 file_ptr file_offset, offset2;
144 size_t real_size;
145 int fd;
93509525
KD
146
147 /* Find the real file and the real offset into it. */
148 while (abfd->my_archive != NULL)
149 {
150 offset += abfd->origin;
151 abfd = abfd->my_archive;
152 }
182a0099
AM
153
154 /* Seek into the file, to ensure it is open if cacheable. */
155 if (abfd->iostream == NULL
156 && (abfd->iovec == NULL
157 || abfd->iovec->bseek (abfd, offset, SEEK_SET) != 0))
103ae312 158 goto free_and_fail;
93509525 159
103ae312 160 fd = fileno ((FILE *) abfd->iostream);
93509525
KD
161 /* Compute offsets and size for mmap and for the user's data. */
162 offset2 = offset % pagesize;
163 if (offset2 < 0)
164 abort ();
165 file_offset = offset - offset2;
166 real_size = offset + size - file_offset;
167 real_size = real_size + pagesize - 1;
168 real_size -= real_size % pagesize;
169
170 /* If we're re-using a memory region, make sure it's big enough. */
103ae312 171 if (i->data != NULL && i->size < size)
93509525
KD
172 {
173 munmap (i->data, i->size);
103ae312 174 i->data = NULL;
93509525
KD
175 }
176 i->data = mmap (i->data, real_size,
177 writable ? PROT_WRITE | PROT_READ : PROT_READ,
178 (writable
179 ? MAP_FILE | MAP_PRIVATE
180 : MAP_FILE | MAP_SHARED),
181 fd, file_offset);
c58b9523 182 if (i->data == (void *) -1)
93509525
KD
183 {
184 /* An error happened. Report it, or try using malloc, or
185 something. */
186 bfd_set_error (bfd_error_system_call);
93509525
KD
187 windowp->data = 0;
188 if (debug_windows)
189 fprintf (stderr, "\t\tmmap failed!\n");
103ae312 190 goto free_and_fail;
93509525
KD
191 }
192 if (debug_windows)
193 fprintf (stderr, "\n\tmapped %ld at %p, offset is %ld\n",
194 (long) real_size, i->data, (long) offset2);
195 i->size = real_size;
c58b9523 196 windowp->data = (bfd_byte *) i->data + offset2;
93509525
KD
197 windowp->size = size;
198 i->mapped = 1;
103ae312
NC
199 i->refcount = 1;
200 windowp->i = i;
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)
103ae312
NC
231 {
232 windowp->i = i;
233 return TRUE;
234 }
235 goto free_and_fail;
93509525 236 }
515ef31d 237 i->refcount = 1;
93509525 238 if (bfd_seek (abfd, offset, SEEK_SET) != 0)
103ae312 239 goto free_and_fail;
93509525
KD
240 i->size = bfd_bread (i->data, size, abfd);
241 if (i->size != size)
103ae312 242 goto free_and_fail;
93509525
KD
243 i->mapped = 0;
244#ifdef HAVE_MPROTECT
245 if (!writable)
246 {
247 if (debug_windows)
248 fprintf (stderr, "\tmprotect (%p, %ld, PROT_READ)\n", i->data,
249 (long) i->size);
250 mprotect (i->data, i->size, PROT_READ);
251 }
252#endif
253 windowp->data = i->data;
254 windowp->size = i->size;
103ae312 255 windowp->i = i;
b34976b6 256 return TRUE;
103ae312
NC
257
258 free_and_fail:
259 /* We have a bfd_window_internal, but an error occurred. Free it. */
260 free (i);
261 return FALSE;
93509525
KD
262}
263
264#endif /* USE_MMAP */
This page took 0.378005 seconds and 4 git commands to generate.