]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/processor-trace/libipt/src/posix/pt_section_posix.c
THIS BRANCH IS OBSOLETE, PLEASE READ:
[FreeBSD/FreeBSD.git] / contrib / processor-trace / libipt / src / posix / pt_section_posix.c
1 /*
2  * Copyright (c) 2013-2019, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  * Redistributions of source code must retain the above copyright notice,
8  *    this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright notice,
10  *    this list of conditions and the following disclaimer in the documentation
11  *    and/or other materials provided with the distribution.
12  *  * Neither the name of Intel Corporation nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "pt_section.h"
30 #include "pt_section_posix.h"
31 #include "pt_section_file.h"
32
33 #include "intel-pt.h"
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <limits.h>
39 #include <sys/types.h>
40 #include <sys/mman.h>
41 #include <fcntl.h>
42 #include <unistd.h>
43
44
45 int pt_section_mk_status(void **pstatus, uint64_t *psize, const char *filename)
46 {
47         struct pt_sec_posix_status *status;
48         struct stat buffer;
49         int errcode;
50
51         if (!pstatus || !psize)
52                 return -pte_internal;
53
54         errcode = stat(filename, &buffer);
55         if (errcode < 0)
56                 return -pte_bad_file;
57
58         if (buffer.st_size < 0)
59                 return -pte_bad_image;
60
61         status = malloc(sizeof(*status));
62         if (!status)
63                 return -pte_nomem;
64
65         status->stat = buffer;
66
67         *pstatus = status;
68         *psize = (uint64_t) buffer.st_size;
69
70         return 0;
71 }
72
73 static int check_file_status(struct pt_section *section, int fd)
74 {
75         struct pt_sec_posix_status *status;
76         struct stat stat;
77         int errcode;
78
79         if (!section)
80                 return -pte_internal;
81
82         errcode = fstat(fd, &stat);
83         if (errcode)
84                 return -pte_bad_file;
85
86         status = section->status;
87         if (!status)
88                 return -pte_internal;
89
90         if (stat.st_size != status->stat.st_size)
91                 return -pte_bad_image;
92
93         if (stat.st_mtime != status->stat.st_mtime)
94                 return -pte_bad_image;
95
96         return 0;
97 }
98
99 int pt_sec_posix_map(struct pt_section *section, int fd)
100 {
101         struct pt_sec_posix_mapping *mapping;
102         uint64_t offset, size, adjustment;
103         uint8_t *base;
104         long page_size;
105         int errcode;
106
107         if (!section)
108                 return -pte_internal;
109
110         offset = section->offset;
111         size = section->size;
112
113         page_size = sysconf(_SC_PAGESIZE);
114         if (page_size < 0)
115                 return -pte_bad_config;
116
117         adjustment = offset % (uint64_t) page_size;
118
119         offset -= adjustment;
120         size += adjustment;
121
122         /* The section is supposed to fit into the file so we shouldn't
123          * see any overflows, here.
124          */
125         if (size < section->size)
126                 return -pte_internal;
127
128         if (SIZE_MAX < size)
129                 return -pte_nomem;
130
131         if (INT_MAX < offset)
132                 return -pte_nomem;
133
134         base = mmap(NULL, (size_t) size, PROT_READ, MAP_SHARED, fd,
135                     (off_t) offset);
136         if (base == MAP_FAILED)
137                 return -pte_nomem;
138
139         mapping = malloc(sizeof(*mapping));
140         if (!mapping) {
141                 errcode = -pte_nomem;
142                 goto out_map;
143         }
144
145         mapping->base = base;
146         mapping->size = size;
147         mapping->begin = base + adjustment;
148         mapping->end = base + size;
149
150         section->mapping = mapping;
151         section->unmap = pt_sec_posix_unmap;
152         section->read = pt_sec_posix_read;
153         section->memsize = pt_sec_posix_memsize;
154
155         return 0;
156
157 out_map:
158         munmap(base, (size_t) size);
159         return errcode;
160 }
161
162 static int pt_sec_posix_map_success(struct pt_section *section)
163 {
164         uint16_t mcount;
165         int errcode, status;
166
167         if (!section)
168                 return -pte_internal;
169
170         mcount = section->mcount + 1;
171         if (!mcount) {
172                 (void) pt_section_unlock(section);
173                 return -pte_overflow;
174         }
175
176         section->mcount = mcount;
177
178         errcode = pt_section_unlock(section);
179         if (errcode < 0)
180                 return errcode;
181
182         status = pt_section_on_map(section);
183         if (status < 0) {
184                 /* We had to release the section lock for pt_section_on_map() so
185                  * @section may have meanwhile been mapped by other threads.
186                  *
187                  * We still want to return the error so we release our mapping.
188                  * Our caller does not yet know whether pt_section_map()
189                  * succeeded.
190                  */
191                 (void) pt_section_unmap(section);
192                 return status;
193         }
194
195         return 0;
196 }
197
198 int pt_section_map(struct pt_section *section)
199 {
200         const char *filename;
201         FILE *file;
202         int fd, errcode;
203
204         if (!section)
205                 return -pte_internal;
206
207         errcode = pt_section_lock(section);
208         if (errcode < 0)
209                 return errcode;
210
211         if (section->mcount)
212                 return pt_sec_posix_map_success(section);
213
214         if (section->mapping)
215                 goto out_unlock;
216
217         filename = section->filename;
218         if (!filename)
219                 goto out_unlock;
220
221         errcode = -pte_bad_file;
222         fd = open(filename, O_RDONLY);
223         if (fd == -1)
224                 goto out_unlock;
225
226         errcode = check_file_status(section, fd);
227         if (errcode < 0)
228                 goto out_fd;
229
230         /* We close the file on success.  This does not unmap the section. */
231         errcode = pt_sec_posix_map(section, fd);
232         if (!errcode) {
233                 close(fd);
234
235                 return pt_sec_posix_map_success(section);
236         }
237
238         /* Fall back to file based sections - report the original error
239          * if we fail to convert the file descriptor.
240          */
241         file = fdopen(fd, "rb");
242         if (!file) {
243                 errcode = -pte_bad_file;
244                 goto out_fd;
245         }
246
247         /* We need to keep the file open on success.  It will be closed when
248          * the section is unmapped.
249          */
250         errcode = pt_sec_file_map(section, file);
251         if (!errcode)
252                 return pt_sec_posix_map_success(section);
253
254         fclose(file);
255         goto out_unlock;
256
257 out_fd:
258         close(fd);
259
260 out_unlock:
261         (void) pt_section_unlock(section);
262         return errcode;
263 }
264
265 int pt_sec_posix_unmap(struct pt_section *section)
266 {
267         struct pt_sec_posix_mapping *mapping;
268
269         if (!section)
270                 return -pte_internal;
271
272         mapping = section->mapping;
273         if (!mapping || !section->unmap || !section->read || !section->memsize)
274                 return -pte_internal;
275
276         section->mapping = NULL;
277         section->unmap = NULL;
278         section->read = NULL;
279         section->memsize = NULL;
280
281         munmap(mapping->base, (size_t) mapping->size);
282         free(mapping);
283
284         return 0;
285 }
286
287 int pt_sec_posix_read(const struct pt_section *section, uint8_t *buffer,
288                       uint16_t size, uint64_t offset)
289 {
290         struct pt_sec_posix_mapping *mapping;
291         const uint8_t *begin;
292
293         if (!buffer || !section)
294                 return -pte_internal;
295
296         mapping = section->mapping;
297         if (!mapping)
298                 return -pte_internal;
299
300         /* We already checked in pt_section_read() that the requested memory
301          * lies within the section's boundaries.
302          *
303          * And we checked that the entire section was mapped.  There's no need
304          * to check for overflows, again.
305          */
306         begin = mapping->begin + offset;
307
308         memcpy(buffer, begin, size);
309         return (int) size;
310 }
311
312 int pt_sec_posix_memsize(const struct pt_section *section, uint64_t *size)
313 {
314         struct pt_sec_posix_mapping *mapping;
315         const uint8_t *begin, *end;
316
317         if (!section || !size)
318                 return -pte_internal;
319
320         mapping = section->mapping;
321         if (!mapping)
322                 return -pte_internal;
323
324         begin = mapping->base;
325         end = mapping->end;
326
327         if (!begin || !end || end < begin)
328                 return -pte_internal;
329
330         *size = (uint64_t) (end - begin);
331
332         return 0;
333 }