diff options
Diffstat (limited to 'libipt/src/posix')
-rw-r--r-- | libipt/src/posix/pt_cpuid.c | 37 | ||||
-rw-r--r-- | libipt/src/posix/pt_section_posix.c | 333 |
2 files changed, 370 insertions, 0 deletions
diff --git a/libipt/src/posix/pt_cpuid.c b/libipt/src/posix/pt_cpuid.c new file mode 100644 index 0000000000000..9334e0d4fac2a --- /dev/null +++ b/libipt/src/posix/pt_cpuid.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pt_cpuid.h" + +#include <cpuid.h> + +extern void pt_cpuid(uint32_t leaf, uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + __get_cpuid(leaf, eax, ebx, ecx, edx); +} diff --git a/libipt/src/posix/pt_section_posix.c b/libipt/src/posix/pt_section_posix.c new file mode 100644 index 0000000000000..651f2546837c8 --- /dev/null +++ b/libipt/src/posix/pt_section_posix.c @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2013-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pt_section.h" +#include "pt_section_posix.h" +#include "pt_section_file.h" + +#include "intel-pt.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <unistd.h> + + +int pt_section_mk_status(void **pstatus, uint64_t *psize, const char *filename) +{ + struct pt_sec_posix_status *status; + struct stat buffer; + int errcode; + + if (!pstatus || !psize) + return -pte_internal; + + errcode = stat(filename, &buffer); + if (errcode < 0) + return -pte_bad_file; + + if (buffer.st_size < 0) + return -pte_bad_image; + + status = malloc(sizeof(*status)); + if (!status) + return -pte_nomem; + + status->stat = buffer; + + *pstatus = status; + *psize = (uint64_t) buffer.st_size; + + return 0; +} + +static int check_file_status(struct pt_section *section, int fd) +{ + struct pt_sec_posix_status *status; + struct stat stat; + int errcode; + + if (!section) + return -pte_internal; + + errcode = fstat(fd, &stat); + if (errcode) + return -pte_bad_file; + + status = section->status; + if (!status) + return -pte_internal; + + if (stat.st_size != status->stat.st_size) + return -pte_bad_image; + + if (stat.st_mtime != status->stat.st_mtime) + return -pte_bad_image; + + return 0; +} + +int pt_sec_posix_map(struct pt_section *section, int fd) +{ + struct pt_sec_posix_mapping *mapping; + uint64_t offset, size, adjustment; + uint8_t *base; + long page_size; + int errcode; + + if (!section) + return -pte_internal; + + offset = section->offset; + size = section->size; + + page_size = sysconf(_SC_PAGESIZE); + if (page_size < 0) + return -pte_bad_config; + + adjustment = offset % (uint64_t) page_size; + + offset -= adjustment; + size += adjustment; + + /* The section is supposed to fit into the file so we shouldn't + * see any overflows, here. + */ + if (size < section->size) + return -pte_internal; + + if (SIZE_MAX < size) + return -pte_nomem; + + if (INT_MAX < offset) + return -pte_nomem; + + base = mmap(NULL, (size_t) size, PROT_READ, MAP_SHARED, fd, + (off_t) offset); + if (base == MAP_FAILED) + return -pte_nomem; + + mapping = malloc(sizeof(*mapping)); + if (!mapping) { + errcode = -pte_nomem; + goto out_map; + } + + mapping->base = base; + mapping->size = size; + mapping->begin = base + adjustment; + mapping->end = base + size; + + section->mapping = mapping; + section->unmap = pt_sec_posix_unmap; + section->read = pt_sec_posix_read; + section->memsize = pt_sec_posix_memsize; + + return 0; + +out_map: + munmap(base, (size_t) size); + return errcode; +} + +static int pt_sec_posix_map_success(struct pt_section *section) +{ + uint16_t mcount; + int errcode, status; + + if (!section) + return -pte_internal; + + mcount = section->mcount + 1; + if (!mcount) { + (void) pt_section_unlock(section); + return -pte_overflow; + } + + section->mcount = mcount; + + errcode = pt_section_unlock(section); + if (errcode < 0) + return errcode; + + status = pt_section_on_map(section); + if (status < 0) { + /* We had to release the section lock for pt_section_on_map() so + * @section may have meanwhile been mapped by other threads. + * + * We still want to return the error so we release our mapping. + * Our caller does not yet know whether pt_section_map() + * succeeded. + */ + (void) pt_section_unmap(section); + return status; + } + + return 0; +} + +int pt_section_map(struct pt_section *section) +{ + const char *filename; + FILE *file; + int fd, errcode; + + if (!section) + return -pte_internal; + + errcode = pt_section_lock(section); + if (errcode < 0) + return errcode; + + if (section->mcount) + return pt_sec_posix_map_success(section); + + if (section->mapping) + goto out_unlock; + + filename = section->filename; + if (!filename) + goto out_unlock; + + errcode = -pte_bad_file; + fd = open(filename, O_RDONLY); + if (fd == -1) + goto out_unlock; + + errcode = check_file_status(section, fd); + if (errcode < 0) + goto out_fd; + + /* We close the file on success. This does not unmap the section. */ + errcode = pt_sec_posix_map(section, fd); + if (!errcode) { + close(fd); + + return pt_sec_posix_map_success(section); + } + + /* Fall back to file based sections - report the original error + * if we fail to convert the file descriptor. + */ + file = fdopen(fd, "rb"); + if (!file) { + errcode = -pte_bad_file; + goto out_fd; + } + + /* We need to keep the file open on success. It will be closed when + * the section is unmapped. + */ + errcode = pt_sec_file_map(section, file); + if (!errcode) + return pt_sec_posix_map_success(section); + + fclose(file); + goto out_unlock; + +out_fd: + close(fd); + +out_unlock: + (void) pt_section_unlock(section); + return errcode; +} + +int pt_sec_posix_unmap(struct pt_section *section) +{ + struct pt_sec_posix_mapping *mapping; + + if (!section) + return -pte_internal; + + mapping = section->mapping; + if (!mapping || !section->unmap || !section->read || !section->memsize) + return -pte_internal; + + section->mapping = NULL; + section->unmap = NULL; + section->read = NULL; + section->memsize = NULL; + + munmap(mapping->base, (size_t) mapping->size); + free(mapping); + + return 0; +} + +int pt_sec_posix_read(const struct pt_section *section, uint8_t *buffer, + uint16_t size, uint64_t offset) +{ + struct pt_sec_posix_mapping *mapping; + const uint8_t *begin; + + if (!buffer || !section) + return -pte_internal; + + mapping = section->mapping; + if (!mapping) + return -pte_internal; + + /* We already checked in pt_section_read() that the requested memory + * lies within the section's boundaries. + * + * And we checked that the entire section was mapped. There's no need + * to check for overflows, again. + */ + begin = mapping->begin + offset; + + memcpy(buffer, begin, size); + return (int) size; +} + +int pt_sec_posix_memsize(const struct pt_section *section, uint64_t *size) +{ + struct pt_sec_posix_mapping *mapping; + const uint8_t *begin, *end; + + if (!section || !size) + return -pte_internal; + + mapping = section->mapping; + if (!mapping) + return -pte_internal; + + begin = mapping->base; + end = mapping->end; + + if (!begin || !end || end < begin) + return -pte_internal; + + *size = (uint64_t) (end - begin); + + return 0; +} |