xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/src/Data_window.cc (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
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