]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - bfd/bfdwin.c
bfd: Use MAP_FAILED for mmap failure
[thirdparty/binutils-gdb.git] / bfd / bfdwin.c
CommitLineData
93509525 1/* Support for memory-mapped windows into a BFD.
fd67aa11 2 Copyright (C) 1995-2024 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
93509525
KD
34static int debug_windows;
35
36/* The idea behind the next and refcount fields is that one mapped
37 region can suffice for multiple read-only windows or multiple
38 non-overlapping read-write windows. It's not implemented yet
39 though. */
40
41/*
717d4bd6
AM
42INTERNAL
43.typedef struct _bfd_window_internal
44.{
93509525 45. struct _bfd_window_internal *next;
c58b9523 46. void *data;
93509525
KD
47. bfd_size_type size;
48. int refcount : 31; {* should be enough... *}
49. unsigned mapped : 1; {* 1 = mmap, 0 = malloc *}
717d4bd6
AM
50.}
51.bfd_window_internal;
52.
53
54EXTERNAL
55.struct _bfd_window_internal;
56.
57.typedef struct _bfd_window
58.{
59. {* What the user asked for. *}
60. void *data;
61. bfd_size_type size;
62. {* The actual window used by BFD. Small user-requested read-only
63. regions sharing a page may share a single window into the object
64. file. Read-write versions shouldn't until I've fixed things to
65. keep track of which portions have been claimed by the
66. application; don't want to give the same region back when the
67. application wants two writable copies! *}
68. struct _bfd_window_internal *i;
69.}
70.bfd_window;
71.
72*/
73
74/*
75FUNCTION
76 bfd_init_window
77
78SYNOPSIS
79 void bfd_init_window (bfd_window *);
80
81DESCRIPTION
82 Initialise mmap window.
93509525
KD
83*/
84
85void
c58b9523 86bfd_init_window (bfd_window *windowp)
93509525
KD
87{
88 windowp->data = 0;
89 windowp->i = 0;
90 windowp->size = 0;
91}
92
717d4bd6
AM
93/*
94FUNCTION
95 bfd_free_window
96
97SYNOPSIS
98 void bfd_free_window (bfd_window *);
99
100DESCRIPTION
101 Finalise mmap window struct.
102*/
103
93509525 104void
c58b9523 105bfd_free_window (bfd_window *windowp)
93509525
KD
106{
107 bfd_window_internal *i = windowp->i;
108 windowp->i = 0;
109 windowp->data = 0;
110 if (i == 0)
111 return;
112 i->refcount--;
113 if (debug_windows)
114 fprintf (stderr, "freeing window @%p<%p,%lx,%p>\n",
848f5748 115 windowp, windowp->data, (unsigned long) windowp->size, windowp->i);
93509525
KD
116 if (i->refcount != 0)
117 return;
118
119 if (i->mapped)
120 {
121#ifdef HAVE_MMAP
122 munmap (i->data, i->size);
123 goto no_free;
124#else
125 abort ();
126#endif
127 }
128#ifdef HAVE_MPROTECT
129 mprotect (i->data, i->size, PROT_READ | PROT_WRITE);
130#endif
131 free (i->data);
132#ifdef HAVE_MMAP
133 no_free:
134#endif
135 i->data = 0;
136 /* There should be no more references to i at this point. */
137 free (i);
138}
139
717d4bd6
AM
140/*
141FUNCTION
142 bfd_get_file_window
143
144SYNOPSIS
145 bool bfd_get_file_window
146 (bfd *, file_ptr, bfd_size_type, bfd_window *, bool {*writable*});
147
148DESCRIPTION
149 mmap from a bfd's iostream.
150*/
93509525 151
0a1b45a2 152bool
c58b9523
AM
153bfd_get_file_window (bfd *abfd,
154 file_ptr offset,
155 bfd_size_type size,
156 bfd_window *windowp,
0a1b45a2 157 bool writable)
93509525 158{
717d4bd6 159 static int ok_to_map = 1;
93509525
KD
160 static size_t pagesize;
161 bfd_window_internal *i = windowp->i;
162 bfd_size_type size_to_alloc = size;
163
164 if (debug_windows)
165 fprintf (stderr, "bfd_get_file_window (%p, %6ld, %6ld, %p<%p,%lx,%p>, %d)",
166 abfd, (long) offset, (long) size,
167 windowp, windowp->data, (unsigned long) windowp->size,
168 windowp->i, writable);
169
170 /* Make sure we know the page size, so we can be friendly to mmap. */
171 if (pagesize == 0)
172 pagesize = getpagesize ();
173 if (pagesize == 0)
174 abort ();
175
103ae312 176 if (i == NULL)
93509525 177 {
c58b9523 178 i = bfd_zmalloc (sizeof (bfd_window_internal));
103ae312 179 if (i == NULL)
0a1b45a2 180 return false;
103ae312 181 i->data = NULL;
93509525
KD
182 }
183#ifdef HAVE_MMAP
184 if (ok_to_map
103ae312 185 && (i->data == NULL || i->mapped == 1)
93509525
KD
186 && (abfd->flags & BFD_IN_MEMORY) == 0)
187 {
188 file_ptr file_offset, offset2;
189 size_t real_size;
190 int fd;
93509525
KD
191
192 /* Find the real file and the real offset into it. */
b0cffb47
AM
193 while (abfd->my_archive != NULL
194 && !bfd_is_thin_archive (abfd->my_archive))
93509525
KD
195 {
196 offset += abfd->origin;
197 abfd = abfd->my_archive;
198 }
4d095f5b 199 offset += abfd->origin;
182a0099
AM
200
201 /* Seek into the file, to ensure it is open if cacheable. */
202 if (abfd->iostream == NULL
203 && (abfd->iovec == NULL
204 || abfd->iovec->bseek (abfd, offset, SEEK_SET) != 0))
103ae312 205 goto free_and_fail;
93509525 206
103ae312 207 fd = fileno ((FILE *) abfd->iostream);
93509525
KD
208 /* Compute offsets and size for mmap and for the user's data. */
209 offset2 = offset % pagesize;
210 if (offset2 < 0)
211 abort ();
212 file_offset = offset - offset2;
213 real_size = offset + size - file_offset;
214 real_size = real_size + pagesize - 1;
215 real_size -= real_size % pagesize;
216
217 /* If we're re-using a memory region, make sure it's big enough. */
103ae312 218 if (i->data != NULL && i->size < size)
93509525
KD
219 {
220 munmap (i->data, i->size);
103ae312 221 i->data = NULL;
93509525
KD
222 }
223 i->data = mmap (i->data, real_size,
224 writable ? PROT_WRITE | PROT_READ : PROT_READ,
225 (writable
226 ? MAP_FILE | MAP_PRIVATE
227 : MAP_FILE | MAP_SHARED),
228 fd, file_offset);
2e384d4f 229 if (i->data == MAP_FAILED)
93509525
KD
230 {
231 /* An error happened. Report it, or try using malloc, or
232 something. */
233 bfd_set_error (bfd_error_system_call);
93509525
KD
234 windowp->data = 0;
235 if (debug_windows)
236 fprintf (stderr, "\t\tmmap failed!\n");
103ae312 237 goto free_and_fail;
93509525
KD
238 }
239 if (debug_windows)
240 fprintf (stderr, "\n\tmapped %ld at %p, offset is %ld\n",
241 (long) real_size, i->data, (long) offset2);
242 i->size = real_size;
c58b9523 243 windowp->data = (bfd_byte *) i->data + offset2;
93509525
KD
244 windowp->size = size;
245 i->mapped = 1;
103ae312
NC
246 i->refcount = 1;
247 windowp->i = i;
0a1b45a2 248 return true;
93509525
KD
249 }
250 else if (debug_windows)
251 {
252 if (ok_to_map)
253 fprintf (stderr, _("not mapping: data=%lx mapped=%d\n"),
254 (unsigned long) i->data, (int) i->mapped);
255 else
256 fprintf (stderr, _("not mapping: env var not set\n"));
257 }
258#else
259 ok_to_map = 0;
260#endif
261
262#ifdef HAVE_MPROTECT
263 if (!writable)
264 {
265 size_to_alloc += pagesize - 1;
266 size_to_alloc -= size_to_alloc % pagesize;
267 }
268#endif
269 if (debug_windows)
270 fprintf (stderr, "\n\t%s(%6ld)",
271 i->data ? "realloc" : " malloc", (long) size_to_alloc);
515ef31d 272 i->data = bfd_realloc_or_free (i->data, size_to_alloc);
93509525
KD
273 if (debug_windows)
274 fprintf (stderr, "\t-> %p\n", i->data);
93509525
KD
275 if (i->data == NULL)
276 {
277 if (size_to_alloc == 0)
103ae312
NC
278 {
279 windowp->i = i;
0a1b45a2 280 return true;
103ae312
NC
281 }
282 goto free_and_fail;
93509525 283 }
515ef31d 284 i->refcount = 1;
93509525 285 if (bfd_seek (abfd, offset, SEEK_SET) != 0)
103ae312 286 goto free_and_fail;
226f9f4f 287 i->size = bfd_read (i->data, size, abfd);
93509525 288 if (i->size != size)
103ae312 289 goto free_and_fail;
93509525
KD
290 i->mapped = 0;
291#ifdef HAVE_MPROTECT
292 if (!writable)
293 {
294 if (debug_windows)
295 fprintf (stderr, "\tmprotect (%p, %ld, PROT_READ)\n", i->data,
296 (long) i->size);
297 mprotect (i->data, i->size, PROT_READ);
298 }
299#endif
300 windowp->data = i->data;
301 windowp->size = i->size;
103ae312 302 windowp->i = i;
0a1b45a2 303 return true;
103ae312
NC
304
305 free_and_fail:
306 /* We have a bfd_window_internal, but an error occurred. Free it. */
307 free (i);
0a1b45a2 308 return false;
93509525
KD
309}
310
311#endif /* USE_MMAP */