1 /* 2 * Copyright (c) 2015-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_file.h" 31 32 #include "intel-pt.h" 33 34 #include <stdlib.h> 35 #include <stdio.h> 36 37 38 /* This is a variation of ptunit-section.c. 39 * 40 * We provide pt_section_map() et.al. that are normally provided by mmap-based 41 * section implementations. Our implementation falls back to file-based 42 * sections so we're able to test them. 43 * 44 * The actual test is in ptunit-section.c. 45 */ 46 47 /* The file status used for detecting changes to a file between unmap and map. 48 * 49 * In our case, the changes always affect the size of the file. 50 */ 51 struct pt_file_status { 52 /* The size in bytes. */ 53 long size; 54 }; 55 56 int pt_section_mk_status(void **pstatus, uint64_t *psize, const char *filename) 57 { 58 struct pt_file_status *status; 59 FILE *file; 60 long size; 61 int errcode; 62 63 if (!pstatus || !psize) 64 return -pte_internal; 65 66 file = fopen(filename, "rb"); 67 if (!file) 68 return -pte_bad_image; 69 70 errcode = fseek(file, 0, SEEK_END); 71 if (errcode) { 72 errcode = -pte_bad_image; 73 goto out_file; 74 } 75 76 size = ftell(file); 77 if (size < 0) { 78 errcode = -pte_bad_image; 79 goto out_file; 80 } 81 82 status = malloc(sizeof(*status)); 83 if (!status) { 84 errcode = -pte_nomem; 85 goto out_file; 86 } 87 88 status->size = size; 89 90 *pstatus = status; 91 *psize = (uint64_t) size; 92 93 errcode = 0; 94 95 out_file: 96 fclose(file); 97 return errcode; 98 } 99 100 static int pt_section_map_success(struct pt_section *section) 101 { 102 uint16_t mcount; 103 int errcode, status; 104 105 if (!section) 106 return -pte_internal; 107 108 mcount = section->mcount + 1; 109 if (!mcount) { 110 (void) pt_section_unlock(section); 111 return -pte_overflow; 112 } 113 114 section->mcount = mcount; 115 116 errcode = pt_section_unlock(section); 117 if (errcode < 0) 118 return errcode; 119 120 status = pt_section_on_map(section); 121 if (status < 0) { 122 (void) pt_section_unmap(section); 123 return status; 124 } 125 126 return 0; 127 } 128 129 int pt_section_map(struct pt_section *section) 130 { 131 struct pt_file_status *status; 132 const char *filename; 133 uint16_t mcount; 134 FILE *file; 135 long size; 136 int errcode; 137 138 if (!section) 139 return -pte_internal; 140 141 errcode = pt_section_lock(section); 142 if (errcode < 0) 143 return errcode; 144 145 mcount = section->mcount; 146 if (mcount) 147 return pt_section_map_success(section); 148 149 if (section->mapping) 150 goto out_unlock; 151 152 filename = section->filename; 153 if (!filename) 154 goto out_unlock; 155 156 status = section->status; 157 if (!status) 158 goto out_unlock; 159 160 errcode = -pte_bad_image; 161 file = fopen(filename, "rb"); 162 if (!file) 163 goto out_unlock; 164 165 errcode = fseek(file, 0, SEEK_END); 166 if (errcode) { 167 errcode = -pte_bad_image; 168 goto out_file; 169 } 170 171 errcode = -pte_bad_image; 172 size = ftell(file); 173 if (size < 0) 174 goto out_file; 175 176 if (size != status->size) 177 goto out_file; 178 179 /* We need to keep the file open on success. It will be closed when 180 * the section is unmapped. 181 */ 182 errcode = pt_sec_file_map(section, file); 183 if (!errcode) 184 return pt_section_map_success(section); 185 186 out_file: 187 fclose(file); 188 189 out_unlock: 190 (void) pt_section_unlock(section); 191 return errcode; 192 } 193