1 /* Copyright (C) 2021-2024 Free Software Foundation, Inc.
2 Contributed by Oracle.
3
4 This file is part of GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
20
21 #include "config.h"
22 #include <sys/types.h>
23 #include <sys/mman.h>
24 #include <fcntl.h>
25 #include <unistd.h> // for close();
26
27 #include "util.h"
28 #include "Data_window.h"
29 #include "debug.h"
30
31 enum
32 {
33 MINBUFSIZE = 1 << 16,
34 WIN_ALIGN = 8
35 };
36
Data_window(char * file_name)37 Data_window::Data_window (char *file_name)
38 {
39 Dprintf (DEBUG_DATA_WINDOW, NTXT ("Data_window:%d %s\n"), (int) __LINE__, STR (file_name));
40 page_size = sysconf (_SC_PAGESIZE);
41 need_swap_endian = false;
42 opened = false;
43 fsize = 0;
44 base = NULL;
45 woffset = 0;
46 wsize = 0;
47 basesize = 0;
48 fname = dbe_strdup (file_name);
49 mmap_on_file = false;
50 use_mmap = false;
51 #if DEBUG
52 if (DBE_USE_MMAP)
53 use_mmap = true;
54 #endif /* DEBUG */
55 fd = open64 (fname, O_RDONLY);
56 if (fd == -1)
57 return;
58 fsize = lseek (fd, 0, SEEK_END);
59 if (fsize == 0)
60 {
61 close (fd);
62 fd = -1;
63 return;
64 }
65 opened = true;
66 if (use_mmap)
67 {
68 if (fsize != -1)
69 {
70 base = (void*) mmap (NULL, (size_t) fsize, PROT_READ, MAP_PRIVATE, fd, 0);
71 close (fd);
72 fd = -1;
73 if (base == MAP_FAILED)
74 {
75 base = NULL;
76 use_mmap = false;
77 return;
78 }
79 mmap_on_file = true;
80 wsize = fsize;
81 }
82 }
83 }
84
85 void *
bind(int64_t file_offset,int64_t minSize)86 Data_window::bind (int64_t file_offset, int64_t minSize)
87 {
88 Span span;
89 span.length = fsize - file_offset;
90 span.offset = file_offset;
91 return bind (&span, minSize);
92 }
93
94 void *
bind(Span * span,int64_t minSize)95 Data_window::bind (Span *span, int64_t minSize)
96 {
97 // Do any necessary mapping to access the desired span of data
98 // and return a pointer to the first byte.
99 Dprintf (DEBUG_DATA_WINDOW, NTXT ("Data_window:bind:%d offset=%llx:%lld minSize=%lld \n"),
100 (int) __LINE__, (long long) span->offset, (long long) span->length, (long long) minSize);
101 if (minSize == 0 || span->length < minSize)
102 return NULL;
103
104 if (span->offset < woffset || span->offset + minSize > woffset + wsize)
105 {
106 // Remap the window
107 if (span->offset + minSize > fsize)
108 return NULL;
109 int myfd = fd;
110 if (myfd == -1)
111 {
112 if (fname)
113 myfd = open64 (fname, O_RDONLY, 0);
114 if (myfd == -1)
115 return NULL;
116 }
117 bool remap_failed = true;
118 if (use_mmap)
119 {
120 if (base)
121 {
122 munmap ((caddr_t) base, (size_t) wsize);
123 base = NULL;
124 }
125 woffset = span->offset & ~(page_size - 1);
126 wsize = page_size * ((MINBUFSIZE + page_size - 1) / page_size);
127 if (span->offset + minSize > woffset + wsize)
128 // Extend a window
129 wsize += page_size * ((span->offset + minSize -
130 woffset - wsize + page_size - 1) / page_size);
131 base = (void *) mmap (0, (size_t) wsize, PROT_READ, MAP_SHARED, fd, woffset);
132 if (base == MAP_FAILED)
133 {
134 base = NULL;
135 use_mmap = false;
136 }
137 remap_failed = (base == NULL);
138 }
139 if (remap_failed)
140 {
141 remap_failed = false;
142 woffset = span->offset & ~(WIN_ALIGN - 1);
143 wsize = minSize + (span->offset % WIN_ALIGN);
144 if (wsize < MINBUFSIZE)
145 wsize = MINBUFSIZE;
146 if (wsize > fsize)
147 wsize = fsize;
148 if (basesize < wsize)
149 { // Need to realloc 'base'
150 free (base);
151 basesize = wsize;
152 base = (void *) malloc (basesize);
153 Dprintf (DEBUG_DATA_WINDOW,
154 NTXT ("Data_window:bind:%d realloc basesize=%llx woffset=%lld \n"),
155 (int) __LINE__, (long long) basesize, (long long) woffset);
156 if (base == NULL)
157 {
158 basesize = 0;
159 remap_failed = true;
160 }
161 }
162 if (wsize > fsize - woffset)
163 wsize = fsize - woffset;
164 off_t woff = (off_t) woffset;
165 if (base == NULL || woff != lseek (myfd, woff, SEEK_SET)
166 || wsize != read_from_file (myfd, base, wsize))
167 remap_failed = true;
168 }
169 if (fd == -1)
170 close (myfd);
171 if (remap_failed)
172 {
173 woffset = 0;
174 wsize = 0;
175 return NULL;
176 }
177 }
178 return (void *) ((char*) base + span->offset - woffset);
179 }
180
181 void *
get_data(int64_t offset,int64_t size,void * datap)182 Data_window::get_data (int64_t offset, int64_t size, void *datap)
183 {
184 if (size <= 0)
185 return NULL;
186 void *buf = bind (offset, size);
187 if (buf == NULL)
188 return NULL;
189 if (datap == NULL && !mmap_on_file)
190 // Can be remmaped or reallocated. Need to make a copy
191 datap = (void *) malloc (size);
192 if (datap)
193 {
194 memcpy (datap, buf, (size_t) size);
195 return datap;
196 }
197 return buf;
198 }
199
~Data_window()200 Data_window::~Data_window ()
201 {
202 free (fname);
203 if (fd != -1)
204 close (fd);
205 if (base)
206 {
207 if (use_mmap)
208 munmap ((caddr_t) base, (size_t) wsize);
209 else
210 free (base);
211 }
212 }
213
214 int64_t
get_buf_size()215 Data_window::get_buf_size ()
216 {
217 int64_t sz = MINBUFSIZE;
218 if (sz < basesize)
219 sz = basesize;
220 if (sz > fsize)
221 sz = fsize;
222 return sz;
223 }
224
225 int64_t
copy_to_file(int f,int64_t offset,int64_t size)226 Data_window::copy_to_file (int f, int64_t offset, int64_t size)
227 {
228 long long bsz = get_buf_size ();
229 for (long long n = 0; n < size;)
230 {
231 long long sz = (bsz <= (size - n)) ? bsz : (size - n);
232 void *b = bind (offset + n, sz);
233 if (b == NULL)
234 return n;
235 long long len = write (f, b, sz);
236 if (len <= 0)
237 return n;
238 n += len;
239 }
240 return size;
241 }
242