2 * Copyright (c) 2015-2019, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
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.
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.
29 #include "pt_section.h"
30 #include "pt_section_windows.h"
31 #include "pt_section_file.h"
41 static int pt_sec_windows_fstat(const char *filename, struct _stat *stat)
45 if (!filename || !stat)
48 fd = _open(filename, _O_RDONLY);
52 errcode = _fstat(fd, stat);
62 int pt_section_mk_status(void **pstatus, uint64_t *psize, const char *filename)
64 struct pt_sec_windows_status *status;
68 if (!pstatus || !psize)
71 errcode = pt_sec_windows_fstat(filename, &stat);
76 return -pte_bad_image;
78 status = malloc(sizeof(*status));
85 *psize = stat.st_size;
90 static int check_file_status(struct pt_section *section, int fd)
92 struct pt_sec_windows_status *status;
99 errcode = _fstat(fd, &stat);
101 return -pte_bad_file;
103 status = section->status;
105 return -pte_internal;
107 if (stat.st_size != status->stat.st_size)
108 return -pte_bad_image;
110 if (stat.st_mtime != status->stat.st_mtime)
111 return -pte_bad_image;
116 static DWORD granularity(void)
118 struct _SYSTEM_INFO sysinfo;
120 GetSystemInfo(&sysinfo);
122 return sysinfo.dwAllocationGranularity;
125 int pt_sec_windows_map(struct pt_section *section, int fd)
127 struct pt_sec_windows_mapping *mapping;
128 uint64_t offset, size, adjustment;
135 return -pte_internal;
137 offset = section->offset;
138 size = section->size;
140 adjustment = offset % granularity();
142 offset -= adjustment;
145 /* The section is supposed to fit into the file so we shouldn't
146 * see any overflows, here.
148 if (size < section->size)
149 return -pte_internal;
151 dsize = (DWORD) size;
152 if ((uint64_t) dsize != size)
153 return -pte_internal;
155 fh = (HANDLE) _get_osfhandle(fd);
157 mh = CreateFileMapping(fh, NULL, PAGE_READONLY, 0, 0, NULL);
159 return -pte_bad_image;
161 base = MapViewOfFile(mh, FILE_MAP_READ, (DWORD) (offset >> 32),
162 (DWORD) (uint32_t) offset, dsize);
164 errcode = -pte_bad_image;
168 mapping = malloc(sizeof(*mapping));
170 errcode = -pte_nomem;
176 mapping->base = base;
177 mapping->begin = base + adjustment;
178 mapping->end = base + size;
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;
188 UnmapViewOfFile(base);
195 static int pt_sec_windows_map_success(struct pt_section *section)
201 return -pte_internal;
203 mcount = section->mcount + 1;
205 (void) pt_section_unlock(section);
206 return -pte_overflow;
209 section->mcount = mcount;
211 errcode = pt_section_unlock(section);
215 status = pt_section_on_map(section);
217 /* We had to release the section lock for pt_section_on_map() so
218 * @section may have meanwhile been mapped by other threads.
220 * We still want to return the error so we release our mapping.
221 * Our caller does not yet know whether pt_section_map()
224 (void) pt_section_unmap(section);
231 int pt_section_map(struct pt_section *section)
233 const char *filename;
239 return -pte_internal;
241 errcode = pt_section_lock(section);
246 return pt_sec_windows_map_success(section);
248 if (section->mapping) {
249 errcode = -pte_internal;
253 filename = section->filename;
255 errcode = -pte_internal;
259 fh = CreateFileA(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.
265 * We will detect changes to the file via fstat().
268 fh = CreateFileA(filename, GENERIC_READ, FILE_SHARE_WRITE,
269 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
271 if (fh == INVALID_HANDLE_VALUE) {
272 errcode = -pte_bad_file;
277 fd = _open_osfhandle((intptr_t) fh, _O_RDONLY);
279 errcode = -pte_bad_file;
283 errcode = check_file_status(section, fd);
287 /* We leave the file open on success. It will be closed when the
288 * section is unmapped.
290 errcode = pt_sec_windows_map(section, fd);
292 return pt_sec_windows_map_success(section);
294 /* Fall back to file based sections - report the original error
295 * if we fail to convert the file descriptor.
297 file = _fdopen(fd, "rb");
299 errcode = -pte_bad_file;
303 /* We need to keep the file open on success. It will be closed when
304 * the section is unmapped.
306 errcode = pt_sec_file_map(section, file);
308 return pt_sec_windows_map_success(section);
321 (void) pt_section_unlock(section);
325 int pt_sec_windows_unmap(struct pt_section *section)
327 struct pt_sec_windows_mapping *mapping;
330 return -pte_internal;
332 mapping = section->mapping;
333 if (!mapping || !section->unmap || !section->read || !section->memsize)
334 return -pte_internal;
336 section->mapping = NULL;
337 section->unmap = NULL;
338 section->read = NULL;
339 section->memsize = NULL;
341 UnmapViewOfFile(mapping->begin);
342 CloseHandle(mapping->mh);
349 int pt_sec_windows_read(const struct pt_section *section, uint8_t *buffer,
350 uint16_t size, uint64_t offset)
352 struct pt_sec_windows_mapping *mapping;
353 const uint8_t *begin;
355 if (!buffer || !section)
356 return -pte_internal;
358 mapping = section->mapping;
360 return -pte_internal;
362 /* We already checked in pt_section_read() that the requested memory
363 * lies within the section's boundaries.
365 * And we checked that the entire section was mapped. There's no need
366 * to check for overflows, again.
368 begin = mapping->begin + offset;
370 memcpy(buffer, begin, size);
375 int pt_sec_windows_memsize(const struct pt_section *section, uint64_t *size)
377 struct pt_sec_windows_mapping *mapping;
378 const uint8_t *begin, *end;
380 if (!section || !size)
381 return -pte_internal;
383 mapping = section->mapping;
385 return -pte_internal;
387 begin = mapping->base;
390 if (!begin || !end || end < begin)
391 return -pte_internal;
393 *size = (uint64_t) (end - begin);