libctf: lowest-level memory allocation and debug-dumping wrappers
[external/binutils.git] / libctf / ctf-subr.c
1 /* Simple subrs.
2    Copyright (C) 2019 Free Software Foundation, Inc.
3
4    This file is part of libctf.
5
6    libctf is free software; you can redistribute it and/or modify it under
7    the terms of the GNU General Public License as published by the Free
8    Software Foundation; either version 3, or (at your option) any later
9    version.
10
11    This program is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14    See the 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; see the file COPYING.  If not see
18    <http://www.gnu.org/licenses/>.  */
19
20 #include <ctf-impl.h>
21 #ifdef HAVE_MMAP
22 #include <sys/mman.h>
23 #endif
24 #include <sys/types.h>
25 #include <stdarg.h>
26 #include <string.h>
27 #include <unistd.h>
28
29 static size_t _PAGESIZE _libctf_unused_;
30 int _libctf_debug = 0;                        /* Debugging messages enabled.  */
31
32 _libctf_malloc_ void *
33 ctf_data_alloc (size_t size)
34 {
35   void *ret;
36
37 #ifdef HAVE_MMAP
38   if (_PAGESIZE == 0)
39     _PAGESIZE = sysconf(_SC_PAGESIZE);
40
41   if (size > _PAGESIZE)
42     {
43       ret = mmap (NULL, size, PROT_READ | PROT_WRITE,
44                   MAP_PRIVATE | MAP_ANON, -1, 0);
45       if (ret == MAP_FAILED)
46         ret = NULL;
47     }
48   else
49     ret = calloc (1, size);
50 #else
51   ret = calloc (1, size);
52 #endif
53   return ret;
54 }
55
56 void
57 ctf_data_free (void *buf, size_t size _libctf_unused_)
58 {
59 #ifdef HAVE_MMAP
60   /* Must be the same as the check in ctf_data_alloc().  */
61
62   if (size > _PAGESIZE)
63     (void) munmap (buf, size);
64   else
65     free (buf);
66 #else
67   free (buf);
68 #endif
69 }
70
71 /* Private, read-only mmap from a file, with fallback to copying.
72
73    No handling of page-offset issues at all: the caller must allow for that. */
74
75 _libctf_malloc_ void *
76 ctf_mmap (size_t length, size_t offset, int fd)
77 {
78   void *data;
79
80 #ifdef HAVE_MMAP
81   data = mmap (NULL, length, PROT_READ, MAP_PRIVATE, fd, offset);
82   if (data == MAP_FAILED)
83     data = NULL;
84 #else
85   if ((data = malloc (length)) != NULL)
86     {
87       if (ctf_pread (fd, data, length, offset) <= 0)
88         {
89           free (data);
90           data = NULL;
91         }
92     }
93 #endif
94   return data;
95 }
96
97 void
98 ctf_munmap (void *buf, size_t length _libctf_unused_)
99 {
100 #ifdef HAVE_MMAP
101   (void) munmap (buf, length);
102 #else
103   free (buf);
104 #endif
105 }
106
107 void
108 ctf_data_protect (void *buf, size_t size)
109 {
110 #ifdef HAVE_MMAP
111   /* Must be the same as the check in ctf_data_alloc().  */
112
113   if (size > _PAGESIZE)
114     (void) mprotect (buf, size, PROT_READ);
115 #endif
116 }
117
118 _libctf_malloc_ void *
119 ctf_alloc (size_t size)
120 {
121   return (malloc (size));
122 }
123
124 void
125 ctf_free (void *buf)
126 {
127   free (buf);
128 }
129
130 ssize_t
131 ctf_pread (int fd, void *buf, ssize_t count, off_t offset)
132 {
133   ssize_t len;
134   size_t acc = 0;
135   char *data = (char *) buf;
136
137 #ifdef HAVE_PREAD
138   while (count > 0)
139     {
140       errno = 0;
141       if (((len = pread (fd, data, count, offset)) < 0) &&
142           errno != EINTR)
143           return len;
144       if (errno == EINTR)
145         continue;
146
147       acc += len;
148       if (len == 0)                             /* EOF.  */
149         return acc;
150
151       count -= len;
152       offset += len;
153       data += len;
154     }
155   return acc;
156 #else
157   off_t orig_off;
158
159   if ((orig_off = lseek (fd, 0, SEEK_CUR)) < 0)
160     return -1;
161   if ((lseek (fd, offset, SEEK_SET)) < 0)
162     return -1;
163
164   while (count > 0)
165     {
166       errno = 0;
167       if (((len = read (fd, data, count)) < 0) &&
168           errno != EINTR)
169           return len;
170       if (errno == EINTR)
171         continue;
172
173       acc += len;
174       if (len == 0)                             /* EOF.  */
175         break;
176
177       count -= len;
178       data += len;
179     }
180   if ((lseek (fd, orig_off, SEEK_SET)) < 0)
181     return -1;                                  /* offset is smashed.  */
182 #endif
183
184   return acc;
185 }
186
187 const char *
188 ctf_strerror (int err)
189 {
190   return (const char *) (strerror (err));
191 }
192
193 void
194 libctf_init_debug (void)
195 {
196   static int inited;
197   if (!inited)
198     {
199       _libctf_debug = getenv ("LIBCTF_DEBUG") != NULL;
200       inited = 1;
201     }
202 }
203
204 void ctf_setdebug (int debug)
205 {
206   /* Ensure that libctf_init_debug() has been called, so that we don't get our
207      debugging-on-or-off smashed by the next call.  */
208
209   libctf_init_debug();
210   _libctf_debug = debug;
211   ctf_dprintf ("CTF debugging set to %i\n", debug);
212 }
213
214 int ctf_getdebug (void)
215 {
216   return _libctf_debug;
217 }
218
219 _libctf_printflike_ (1, 2)
220 void ctf_dprintf (const char *format, ...)
221 {
222   if (_libctf_debug)
223     {
224       va_list alist;
225
226       va_start (alist, format);
227       fflush (stdout);
228       (void) fputs ("libctf DEBUG: ", stderr);
229       (void) vfprintf (stderr, format, alist);
230       va_end (alist);
231     }
232 }