]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - bfd/bfdwin.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / bfd / bfdwin.c
CommitLineData
93509525 1/* Support for memory-mapped windows into a BFD.
250d07de 2 Copyright (C) 1995-2021 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. */
b0cffb47
AM
147 while (abfd->my_archive != NULL
148 && !bfd_is_thin_archive (abfd->my_archive))
93509525
KD
149 {
150 offset += abfd->origin;
151 abfd = abfd->my_archive;
152 }
4d095f5b 153 offset += abfd->origin;
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))
103ae312 159 goto free_and_fail;
93509525 160
103ae312 161 fd = fileno ((FILE *) abfd->iostream);
93509525
KD
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. */
103ae312 172 if (i->data != NULL && i->size < size)
93509525
KD
173 {
174 munmap (i->data, i->size);
103ae312 175 i->data = NULL;
93509525
KD
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);
93509525
KD
188 windowp->data = 0;
189 if (debug_windows)
190 fprintf (stderr, "\t\tmmap failed!\n");
103ae312 191 goto free_and_fail;
93509525
KD
192 }
193 if (debug_windows)
194 fprintf (stderr, "\n\tmapped %ld at %p, offset is %ld\n",
195 (long) real_size, i->data, (long) offset2);
196 i->size = real_size;
c58b9523 197 windowp->data = (bfd_byte *) i->data + offset2;
93509525
KD
198 windowp->size = size;
199 i->mapped = 1;
103ae312
NC
200 i->refcount = 1;
201 windowp->i = i;
b34976b6 202 return TRUE;
93509525
KD
203 }
204 else if (debug_windows)
205 {
206 if (ok_to_map)
207 fprintf (stderr, _("not mapping: data=%lx mapped=%d\n"),
208 (unsigned long) i->data, (int) i->mapped);
209 else
210 fprintf (stderr, _("not mapping: env var not set\n"));
211 }
212#else
213 ok_to_map = 0;
214#endif
215
216#ifdef HAVE_MPROTECT
217 if (!writable)
218 {
219 size_to_alloc += pagesize - 1;
220 size_to_alloc -= size_to_alloc % pagesize;
221 }
222#endif
223 if (debug_windows)
224 fprintf (stderr, "\n\t%s(%6ld)",
225 i->data ? "realloc" : " malloc", (long) size_to_alloc);
515ef31d 226 i->data = bfd_realloc_or_free (i->data, size_to_alloc);
93509525
KD
227 if (debug_windows)
228 fprintf (stderr, "\t-> %p\n", i->data);
93509525
KD
229 if (i->data == NULL)
230 {
231 if (size_to_alloc == 0)
103ae312
NC
232 {
233 windowp->i = i;
234 return TRUE;
235 }
236 goto free_and_fail;
93509525 237 }
515ef31d 238 i->refcount = 1;
93509525 239 if (bfd_seek (abfd, offset, SEEK_SET) != 0)
103ae312 240 goto free_and_fail;
93509525
KD
241 i->size = bfd_bread (i->data, size, abfd);
242 if (i->size != size)
103ae312 243 goto free_and_fail;
93509525
KD
244 i->mapped = 0;
245#ifdef HAVE_MPROTECT
246 if (!writable)
247 {
248 if (debug_windows)
249 fprintf (stderr, "\tmprotect (%p, %ld, PROT_READ)\n", i->data,
250 (long) i->size);
251 mprotect (i->data, i->size, PROT_READ);
252 }
253#endif
254 windowp->data = i->data;
255 windowp->size = i->size;
103ae312 256 windowp->i = i;
b34976b6 257 return TRUE;
103ae312
NC
258
259 free_and_fail:
260 /* We have a bfd_window_internal, but an error occurred. Free it. */
261 free (i);
262 return FALSE;
93509525
KD
263}
264
265#endif /* USE_MMAP */