]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/processor-trace/libipt/src/windows/pt_section_windows.c
Update libdialog to 1.3-20180621
[FreeBSD/FreeBSD.git] / contrib / processor-trace / libipt / src / windows / pt_section_windows.c
1 /*
2  * Copyright (c) 2015-2018, 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_windows.h"
31 #include "pt_section_file.h"
32
33 #include "intel-pt.h"
34
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <fcntl.h>
38 #include <io.h>
39
40
41 static int pt_sec_windows_fstat(const char *filename, struct _stat *stat)
42 {
43         int fd, errcode;
44
45         if (!filename || !stat)
46                 return -pte_internal;
47
48         fd = _open(filename, _O_RDONLY);
49         if (fd == -1)
50                 return -pte_bad_image;
51
52         errcode = _fstat(fd, stat);
53
54         _close(fd);
55
56         if (errcode)
57                 return -pte_bad_image;
58
59         return 0;
60 }
61
62 int pt_section_mk_status(void **pstatus, uint64_t *psize, const char *filename)
63 {
64         struct pt_sec_windows_status *status;
65         struct _stat stat;
66         int errcode;
67
68         if (!pstatus || !psize)
69                 return -pte_internal;
70
71         errcode = pt_sec_windows_fstat(filename, &stat);
72         if (errcode < 0)
73                 return errcode;
74
75         if (stat.st_size < 0)
76                 return -pte_bad_image;
77
78         status = malloc(sizeof(*status));
79         if (!status)
80                 return -pte_nomem;
81
82         status->stat = stat;
83
84         *pstatus = status;
85         *psize = stat.st_size;
86
87         return 0;
88 }
89
90 static int check_file_status(struct pt_section *section, int fd)
91 {
92         struct pt_sec_windows_status *status;
93         struct _stat stat;
94         int errcode;
95
96         if (!section)
97                 return -pte_internal;
98
99         errcode = _fstat(fd, &stat);
100         if (errcode)
101                 return -pte_bad_image;
102
103         status = section->status;
104         if (!status)
105                 return -pte_internal;
106
107         if (stat.st_size != status->stat.st_size)
108                 return -pte_bad_image;
109
110         if (stat.st_mtime != status->stat.st_mtime)
111                 return -pte_bad_image;
112
113         return 0;
114 }
115
116 static DWORD granularity(void)
117 {
118         struct _SYSTEM_INFO sysinfo;
119
120         GetSystemInfo(&sysinfo);
121
122         return sysinfo.dwAllocationGranularity;
123 }
124
125 int pt_sec_windows_map(struct pt_section *section, int fd)
126 {
127         struct pt_sec_windows_mapping *mapping;
128         uint64_t offset, size, adjustment;
129         HANDLE fh, mh;
130         DWORD dsize;
131         uint8_t *base;
132         int errcode;
133
134         if (!section)
135                 return -pte_internal;
136
137         offset = section->offset;
138         size = section->size;
139
140         adjustment = offset % granularity();
141
142         offset -= adjustment;
143         size += adjustment;
144
145         /* The section is supposed to fit into the file so we shouldn't
146          * see any overflows, here.
147          */
148         if (size < section->size)
149                 return -pte_internal;
150
151         dsize = (DWORD) size;
152         if ((uint64_t) dsize != size)
153                 return -pte_internal;
154
155         fh = (HANDLE) _get_osfhandle(fd);
156
157         mh = CreateFileMapping(fh, NULL, PAGE_READONLY, 0, 0, NULL);
158         if (!mh)
159                 return -pte_bad_image;
160
161         base = MapViewOfFile(mh, FILE_MAP_READ, (DWORD) (offset >> 32),
162                              (DWORD) (uint32_t) offset, dsize);
163         if (!base) {
164                 errcode = -pte_bad_image;
165                 goto out_mh;
166         }
167
168         mapping = malloc(sizeof(*mapping));
169         if (!mapping) {
170                 errcode = -pte_nomem;
171                 goto out_map;
172         }
173
174         mapping->fd = fd;
175         mapping->mh = mh;
176         mapping->base = base;
177         mapping->begin = base + adjustment;
178         mapping->end = base + size;
179
180         section->mapping = mapping;
181         section->unmap = pt_sec_windows_unmap;
182         section->read = pt_sec_windows_read;
183         section->memsize = pt_sec_windows_memsize;
184
185         return 0;
186
187 out_map:
188         UnmapViewOfFile(base);
189
190 out_mh:
191         CloseHandle(mh);
192         return errcode;
193 }
194
195 static int pt_sec_windows_map_success(struct pt_section *section)
196 {
197         uint16_t mcount;
198         int errcode, status;
199
200         if (!section)
201                 return -pte_internal;
202
203         mcount = section->mcount + 1;
204         if (!mcount) {
205                 (void) pt_section_unlock(section);
206                 return -pte_overflow;
207         }
208
209         section->mcount = mcount;
210
211         errcode = pt_section_unlock(section);
212         if (errcode < 0)
213                 return errcode;
214
215         status = pt_section_on_map(section);
216         if (status < 0) {
217                 /* We had to release the section lock for pt_section_on_map() so
218                  * @section may have meanwhile been mapped by other threads.
219                  *
220                  * We still want to return the error so we release our mapping.
221                  * Our caller does not yet know whether pt_section_map()
222                  * succeeded.
223                  */
224                 (void) pt_section_unmap(section);
225                 return status;
226         }
227
228         return 0;
229 }
230
231 int pt_section_map(struct pt_section *section)
232 {
233         const char *filename;
234         HANDLE fh;
235         FILE *file;
236         int fd, errcode;
237
238         if (!section)
239                 return -pte_internal;
240
241         errcode = pt_section_lock(section);
242         if (errcode < 0)
243                 return errcode;
244
245         if (section->mcount)
246                 return pt_sec_windows_map_success(section);
247
248         if (section->mapping) {
249                 errcode = -pte_internal;
250                 goto out_unlock;
251         }
252
253         filename = section->filename;
254         if (!filename) {
255                 errcode = -pte_internal;
256                 goto out_unlock;
257         }
258
259         fh = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
260                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
261         if (fh == INVALID_HANDLE_VALUE) {
262                 /* We failed to open the file read-only.  Let's try to open it
263                  * read-write; maybe our user has the file open for writing.
264                  *
265                  * We will detect changes to the file via fstat().
266                  */
267
268                 fh = CreateFile(filename, GENERIC_READ, FILE_SHARE_WRITE, NULL,
269                                 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
270                 if (fh == INVALID_HANDLE_VALUE) {
271                         errcode = -pte_bad_image;
272                         goto out_unlock;
273                 }
274         }
275
276         fd = _open_osfhandle((intptr_t) fh, _O_RDONLY);
277         if (fd == -1) {
278                 errcode = -pte_bad_image;
279                 goto out_fh;
280         }
281
282         errcode = check_file_status(section, fd);
283         if (errcode < 0) {
284                 errcode = -pte_bad_image;
285                 goto out_fd;
286         }
287
288         /* We leave the file open on success.  It will be closed when the
289          * section is unmapped.
290          */
291         errcode = pt_sec_windows_map(section, fd);
292         if (!errcode)
293                 return pt_sec_windows_map_success(section);
294
295         /* Fall back to file based sections - report the original error
296          * if we fail to convert the file descriptor.
297          */
298         file = _fdopen(fd, "rb");
299         if (!file) {
300                 errcode = -pte_bad_image;
301                 goto out_fd;
302         }
303
304         /* We need to keep the file open on success.  It will be closed when
305          * the section is unmapped.
306          */
307         errcode = pt_sec_file_map(section, file);
308         if (!errcode)
309                 return pt_sec_windows_map_success(section);
310
311         fclose(file);
312         goto out_unlock;
313
314 out_fd:
315         _close(fd);
316         return errcode;
317
318 out_fh:
319         CloseHandle(fh);
320
321 out_unlock:
322         (void) pt_section_unlock(section);
323         return errcode;
324 }
325
326 int pt_sec_windows_unmap(struct pt_section *section)
327 {
328         struct pt_sec_windows_mapping *mapping;
329
330         if (!section)
331                 return -pte_internal;
332
333         mapping = section->mapping;
334         if (!mapping || !section->unmap || !section->read || !section->memsize)
335                 return -pte_internal;
336
337         section->mapping = NULL;
338         section->unmap = NULL;
339         section->read = NULL;
340         section->memsize = NULL;
341
342         UnmapViewOfFile(mapping->begin);
343         CloseHandle(mapping->mh);
344         _close(mapping->fd);
345         free(mapping);
346
347         return 0;
348 }
349
350 int pt_sec_windows_read(const struct pt_section *section, uint8_t *buffer,
351                       uint16_t size, uint64_t offset)
352 {
353         struct pt_sec_windows_mapping *mapping;
354         const uint8_t *begin;
355
356         if (!buffer || !section)
357                 return -pte_internal;
358
359         mapping = section->mapping;
360         if (!mapping)
361                 return -pte_internal;
362
363         /* We already checked in pt_section_read() that the requested memory
364          * lies within the section's boundaries.
365          *
366          * And we checked that the entire section was mapped.  There's no need
367          * to check for overflows, again.
368          */
369         begin = mapping->begin + offset;
370
371         memcpy(buffer, begin, size);
372         return (int) size;
373 }
374
375
376 int pt_sec_windows_memsize(const struct pt_section *section, uint64_t *size)
377 {
378         struct pt_sec_windows_mapping *mapping;
379         const uint8_t *begin, *end;
380
381         if (!section || !size)
382                 return -pte_internal;
383
384         mapping = section->mapping;
385         if (!mapping)
386                 return -pte_internal;
387
388         begin = mapping->base;
389         end =  mapping->end;
390
391         if (!begin || !end || end < begin)
392                 return -pte_internal;
393
394         *size = (uint64_t) (end - begin);
395
396         return 0;
397 }