2 * Copyright (c) 2013-2018, 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_posix.h"
31 #include "pt_section_file.h"
39 #include <sys/types.h>
45 int pt_section_mk_status(void **pstatus, uint64_t *psize, const char *filename)
47 struct pt_sec_posix_status *status;
51 if (!pstatus || !psize)
54 errcode = stat(filename, &buffer);
58 if (buffer.st_size < 0)
59 return -pte_bad_image;
61 status = malloc(sizeof(*status));
65 status->stat = buffer;
68 *psize = buffer.st_size;
73 static int check_file_status(struct pt_section *section, int fd)
75 struct pt_sec_posix_status *status;
82 errcode = fstat(fd, &stat);
84 return -pte_bad_image;
86 status = section->status;
90 if (stat.st_size != status->stat.st_size)
91 return -pte_bad_image;
93 if (stat.st_mtime != status->stat.st_mtime)
94 return -pte_bad_image;
99 int pt_sec_posix_map(struct pt_section *section, int fd)
101 struct pt_sec_posix_mapping *mapping;
102 uint64_t offset, size, adjustment;
107 return -pte_internal;
109 offset = section->offset;
110 size = section->size;
112 adjustment = offset % sysconf(_SC_PAGESIZE);
114 offset -= adjustment;
117 /* The section is supposed to fit into the file so we shouldn't
118 * see any overflows, here.
120 if (size < section->size)
121 return -pte_internal;
126 if (INT_MAX < offset)
129 base = mmap(NULL, (size_t) size, PROT_READ, MAP_SHARED, fd,
131 if (base == MAP_FAILED)
134 mapping = malloc(sizeof(*mapping));
136 errcode = -pte_nomem;
140 mapping->base = base;
141 mapping->size = size;
142 mapping->begin = base + adjustment;
143 mapping->end = base + size;
145 section->mapping = mapping;
146 section->unmap = pt_sec_posix_unmap;
147 section->read = pt_sec_posix_read;
148 section->memsize = pt_sec_posix_memsize;
153 munmap(base, (size_t) size);
157 static int pt_sec_posix_map_success(struct pt_section *section)
163 return -pte_internal;
165 mcount = section->mcount + 1;
167 (void) pt_section_unlock(section);
168 return -pte_overflow;
171 section->mcount = mcount;
173 errcode = pt_section_unlock(section);
177 status = pt_section_on_map(section);
179 /* We had to release the section lock for pt_section_on_map() so
180 * @section may have meanwhile been mapped by other threads.
182 * We still want to return the error so we release our mapping.
183 * Our caller does not yet know whether pt_section_map()
186 (void) pt_section_unmap(section);
193 int pt_section_map(struct pt_section *section)
195 const char *filename;
200 return -pte_internal;
202 errcode = pt_section_lock(section);
207 return pt_sec_posix_map_success(section);
209 if (section->mapping)
212 filename = section->filename;
216 errcode = -pte_bad_image;
217 fd = open(filename, O_RDONLY);
221 errcode = check_file_status(section, fd);
225 /* We close the file on success. This does not unmap the section. */
226 errcode = pt_sec_posix_map(section, fd);
230 return pt_sec_posix_map_success(section);
233 /* Fall back to file based sections - report the original error
234 * if we fail to convert the file descriptor.
236 file = fdopen(fd, "rb");
240 /* We need to keep the file open on success. It will be closed when
241 * the section is unmapped.
243 errcode = pt_sec_file_map(section, file);
245 return pt_sec_posix_map_success(section);
254 (void) pt_section_unlock(section);
258 int pt_sec_posix_unmap(struct pt_section *section)
260 struct pt_sec_posix_mapping *mapping;
263 return -pte_internal;
265 mapping = section->mapping;
266 if (!mapping || !section->unmap || !section->read || !section->memsize)
267 return -pte_internal;
269 section->mapping = NULL;
270 section->unmap = NULL;
271 section->read = NULL;
272 section->memsize = NULL;
274 munmap(mapping->base, (size_t) mapping->size);
280 int pt_sec_posix_read(const struct pt_section *section, uint8_t *buffer,
281 uint16_t size, uint64_t offset)
283 struct pt_sec_posix_mapping *mapping;
284 const uint8_t *begin;
286 if (!buffer || !section)
287 return -pte_internal;
289 mapping = section->mapping;
291 return -pte_internal;
293 /* We already checked in pt_section_read() that the requested memory
294 * lies within the section's boundaries.
296 * And we checked that the entire section was mapped. There's no need
297 * to check for overflows, again.
299 begin = mapping->begin + offset;
301 memcpy(buffer, begin, size);
305 int pt_sec_posix_memsize(const struct pt_section *section, uint64_t *size)
307 struct pt_sec_posix_mapping *mapping;
308 const uint8_t *begin, *end;
310 if (!section || !size)
311 return -pte_internal;
313 mapping = section->mapping;
315 return -pte_internal;
317 begin = mapping->base;
320 if (!begin || !end || end < begin)
321 return -pte_internal;
323 *size = (uint64_t) (end - begin);