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