2008-11-20 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
28/* Currently, if USE_MMAP is undefined, none if the window stuff is
29 used. Okay, so it's mis-named. At least the command-line option
30 "--without-mmap" is more obvious than "--without-windows" or some
31 such. */
32
33#ifdef USE_MMAP
34
35#undef HAVE_MPROTECT /* code's not tested yet */
36
37#if HAVE_MMAP || HAVE_MPROTECT || HAVE_MADVISE
38#include <sys/mman.h>
39#endif
40
41#ifndef MAP_FILE
42#define MAP_FILE 0
43#endif
44
45static int debug_windows;
46
47/* The idea behind the next and refcount fields is that one mapped
48 region can suffice for multiple read-only windows or multiple
49 non-overlapping read-write windows. It's not implemented yet
50 though. */
51
52/*
53INTERNAL_DEFINITION
54
55.struct _bfd_window_internal {
56. struct _bfd_window_internal *next;
c58b9523 57. void *data;
93509525
KD
58. bfd_size_type size;
59. int refcount : 31; {* should be enough... *}
60. unsigned mapped : 1; {* 1 = mmap, 0 = malloc *}
61.};
62*/
63
64void
c58b9523 65bfd_init_window (bfd_window *windowp)
93509525
KD
66{
67 windowp->data = 0;
68 windowp->i = 0;
69 windowp->size = 0;
70}
71
72void
c58b9523 73bfd_free_window (bfd_window *windowp)
93509525
KD
74{
75 bfd_window_internal *i = windowp->i;
76 windowp->i = 0;
77 windowp->data = 0;
78 if (i == 0)
79 return;
80 i->refcount--;
81 if (debug_windows)
82 fprintf (stderr, "freeing window @%p<%p,%lx,%p>\n",
83 windowp, windowp->data, windowp->size, windowp->i);
84 if (i->refcount != 0)
85 return;
86
87 if (i->mapped)
88 {
89#ifdef HAVE_MMAP
90 munmap (i->data, i->size);
91 goto no_free;
92#else
93 abort ();
94#endif
95 }
96#ifdef HAVE_MPROTECT
97 mprotect (i->data, i->size, PROT_READ | PROT_WRITE);
98#endif
99 free (i->data);
100#ifdef HAVE_MMAP
101 no_free:
102#endif
103 i->data = 0;
104 /* There should be no more references to i at this point. */
105 free (i);
106}
107
108static int ok_to_map = 1;
109
b34976b6 110bfd_boolean
c58b9523
AM
111bfd_get_file_window (bfd *abfd,
112 file_ptr offset,
113 bfd_size_type size,
114 bfd_window *windowp,
115 bfd_boolean writable)
93509525
KD
116{
117 static size_t pagesize;
118 bfd_window_internal *i = windowp->i;
119 bfd_size_type size_to_alloc = size;
120
121 if (debug_windows)
122 fprintf (stderr, "bfd_get_file_window (%p, %6ld, %6ld, %p<%p,%lx,%p>, %d)",
123 abfd, (long) offset, (long) size,
124 windowp, windowp->data, (unsigned long) windowp->size,
125 windowp->i, writable);
126
127 /* Make sure we know the page size, so we can be friendly to mmap. */
128 if (pagesize == 0)
129 pagesize = getpagesize ();
130 if (pagesize == 0)
131 abort ();
132
133 if (i == 0)
134 {
c58b9523 135 i = bfd_zmalloc (sizeof (bfd_window_internal));
93509525
KD
136 windowp->i = i;
137 if (i == 0)
b34976b6 138 return FALSE;
93509525
KD
139 i->data = 0;
140 }
141#ifdef HAVE_MMAP
142 if (ok_to_map
143 && (i->data == 0 || i->mapped == 1)
144 && (abfd->flags & BFD_IN_MEMORY) == 0)
145 {
146 file_ptr file_offset, offset2;
147 size_t real_size;
148 int fd;
93509525
KD
149
150 /* Find the real file and the real offset into it. */
151 while (abfd->my_archive != NULL)
152 {
153 offset += abfd->origin;
154 abfd = abfd->my_archive;
155 }
182a0099
AM
156
157 /* Seek into the file, to ensure it is open if cacheable. */
158 if (abfd->iostream == NULL
159 && (abfd->iovec == NULL
160 || abfd->iovec->bseek (abfd, offset, SEEK_SET) != 0))
3dff57e8 161 return FALSE;
182a0099 162 fd = fileno ((FILE *) abfd->iostream);
93509525
KD
163
164 /* Compute offsets and size for mmap and for the user's data. */
165 offset2 = offset % pagesize;
166 if (offset2 < 0)
167 abort ();
168 file_offset = offset - offset2;
169 real_size = offset + size - file_offset;
170 real_size = real_size + pagesize - 1;
171 real_size -= real_size % pagesize;
172
173 /* If we're re-using a memory region, make sure it's big enough. */
174 if (i->data && i->size < size)
175 {
176 munmap (i->data, i->size);
177 i->data = 0;
178 }
179 i->data = mmap (i->data, real_size,
180 writable ? PROT_WRITE | PROT_READ : PROT_READ,
181 (writable
182 ? MAP_FILE | MAP_PRIVATE
183 : MAP_FILE | MAP_SHARED),
184 fd, file_offset);
c58b9523 185 if (i->data == (void *) -1)
93509525
KD
186 {
187 /* An error happened. Report it, or try using malloc, or
188 something. */
189 bfd_set_error (bfd_error_system_call);
190 i->data = 0;
191 windowp->data = 0;
192 if (debug_windows)
193 fprintf (stderr, "\t\tmmap failed!\n");
b34976b6 194 return FALSE;
93509525
KD
195 }
196 if (debug_windows)
197 fprintf (stderr, "\n\tmapped %ld at %p, offset is %ld\n",
198 (long) real_size, i->data, (long) offset2);
199 i->size = real_size;
c58b9523 200 windowp->data = (bfd_byte *) i->data + offset2;
93509525
KD
201 windowp->size = size;
202 i->mapped = 1;
b34976b6 203 return TRUE;
93509525
KD
204 }
205 else if (debug_windows)
206 {
207 if (ok_to_map)
208 fprintf (stderr, _("not mapping: data=%lx mapped=%d\n"),
209 (unsigned long) i->data, (int) i->mapped);
210 else
211 fprintf (stderr, _("not mapping: env var not set\n"));
212 }
213#else
214 ok_to_map = 0;
215#endif
216
217#ifdef HAVE_MPROTECT
218 if (!writable)
219 {
220 size_to_alloc += pagesize - 1;
221 size_to_alloc -= size_to_alloc % pagesize;
222 }
223#endif
224 if (debug_windows)
225 fprintf (stderr, "\n\t%s(%6ld)",
226 i->data ? "realloc" : " malloc", (long) size_to_alloc);
515ef31d 227 i->data = bfd_realloc_or_free (i->data, size_to_alloc);
93509525
KD
228 if (debug_windows)
229 fprintf (stderr, "\t-> %p\n", i->data);
93509525
KD
230 if (i->data == NULL)
231 {
232 if (size_to_alloc == 0)
b34976b6
AM
233 return TRUE;
234 return FALSE;
93509525 235 }
515ef31d 236 i->refcount = 1;
93509525 237 if (bfd_seek (abfd, offset, SEEK_SET) != 0)
b34976b6 238 return FALSE;
93509525
KD
239 i->size = bfd_bread (i->data, size, abfd);
240 if (i->size != size)
b34976b6 241 return FALSE;
93509525
KD
242 i->mapped = 0;
243#ifdef HAVE_MPROTECT
244 if (!writable)
245 {
246 if (debug_windows)
247 fprintf (stderr, "\tmprotect (%p, %ld, PROT_READ)\n", i->data,
248 (long) i->size);
249 mprotect (i->data, i->size, PROT_READ);
250 }
251#endif
252 windowp->data = i->data;
253 windowp->size = i->size;
b34976b6 254 return TRUE;
93509525
KD
255}
256
257#endif /* USE_MMAP */
This page took 0.257538 seconds and 4 git commands to generate.