1 /* 2 * Copyright (c) 2013-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 <string.h> 36 37 38 static int fmap_init(struct pt_sec_file_mapping *mapping) 39 { 40 if (!mapping) 41 return -pte_internal; 42 43 memset(mapping, 0, sizeof(*mapping)); 44 45 #if defined(FEATURE_THREADS) 46 { 47 int errcode; 48 49 errcode = mtx_init(&mapping->lock, mtx_plain); 50 if (errcode != thrd_success) 51 return -pte_bad_lock; 52 } 53 #endif /* defined(FEATURE_THREADS) */ 54 55 return 0; 56 } 57 58 static void fmap_fini(struct pt_sec_file_mapping *mapping) 59 { 60 if (!mapping) 61 return; 62 63 fclose(mapping->file); 64 65 #if defined(FEATURE_THREADS) 66 67 mtx_destroy(&mapping->lock); 68 69 #endif /* defined(FEATURE_THREADS) */ 70 } 71 72 static int fmap_lock(struct pt_sec_file_mapping *mapping) 73 { 74 if (!mapping) 75 return -pte_internal; 76 77 #if defined(FEATURE_THREADS) 78 { 79 int errcode; 80 81 errcode = mtx_lock(&mapping->lock); 82 if (errcode != thrd_success) 83 return -pte_bad_lock; 84 } 85 #endif /* defined(FEATURE_THREADS) */ 86 87 return 0; 88 } 89 90 static int fmap_unlock(struct pt_sec_file_mapping *mapping) 91 { 92 if (!mapping) 93 return -pte_internal; 94 95 #if defined(FEATURE_THREADS) 96 { 97 int errcode; 98 99 errcode = mtx_unlock(&mapping->lock); 100 if (errcode != thrd_success) 101 return -pte_bad_lock; 102 } 103 #endif /* defined(FEATURE_THREADS) */ 104 105 return 0; 106 } 107 108 int pt_sec_file_map(struct pt_section *section, FILE *file) 109 { 110 struct pt_sec_file_mapping *mapping; 111 uint64_t offset, size; 112 long begin, end, fsize; 113 int errcode; 114 115 if (!section) 116 return -pte_internal; 117 118 mapping = section->mapping; 119 if (mapping) 120 return -pte_internal; 121 122 offset = section->offset; 123 size = section->size; 124 125 begin = (long) offset; 126 end = begin + (long) size; 127 128 /* Check for overflows. */ 129 if ((uint64_t) begin != offset) 130 return -pte_bad_image; 131 132 if ((uint64_t) end != (offset + size)) 133 return -pte_bad_image; 134 135 if (end < begin) 136 return -pte_bad_image; 137 138 /* Validate that the section lies within the file. */ 139 errcode = fseek(file, 0, SEEK_END); 140 if (errcode) 141 return -pte_bad_image; 142 143 fsize = ftell(file); 144 if (fsize < 0) 145 return -pte_bad_image; 146 147 if (fsize < end) 148 return -pte_bad_image; 149 150 mapping = malloc(sizeof(*mapping)); 151 if (!mapping) 152 return -pte_nomem; 153 154 errcode = fmap_init(mapping); 155 if (errcode < 0) 156 goto out_mem; 157 158 mapping->file = file; 159 mapping->begin = begin; 160 mapping->end = end; 161 162 section->mapping = mapping; 163 section->unmap = pt_sec_file_unmap; 164 section->read = pt_sec_file_read; 165 section->memsize = pt_sec_file_memsize; 166 167 return 0; 168 169 out_mem: 170 free(mapping); 171 return errcode; 172 } 173 174 int pt_sec_file_unmap(struct pt_section *section) 175 { 176 struct pt_sec_file_mapping *mapping; 177 178 if (!section) 179 return -pte_internal; 180 181 mapping = section->mapping; 182 183 if (!mapping || !section->unmap || !section->read || !section->memsize) 184 return -pte_internal; 185 186 section->mapping = NULL; 187 section->unmap = NULL; 188 section->read = NULL; 189 section->memsize = NULL; 190 191 fmap_fini(mapping); 192 free(mapping); 193 194 return 0; 195 } 196 197 int pt_sec_file_read(const struct pt_section *section, uint8_t *buffer, 198 uint16_t size, uint64_t offset) 199 { 200 struct pt_sec_file_mapping *mapping; 201 FILE *file; 202 long begin; 203 size_t read; 204 int errcode; 205 206 if (!buffer || !section) 207 return -pte_internal; 208 209 mapping = section->mapping; 210 if (!mapping) 211 return -pte_internal; 212 213 file = mapping->file; 214 215 /* We already checked in pt_section_read() that the requested memory 216 * lies within the section's boundaries. 217 * 218 * And we checked that the file covers the entire section in 219 * pt_sec_file_map(). There's no need to check for overflows, again. 220 */ 221 begin = mapping->begin + (long) offset; 222 223 errcode = fmap_lock(mapping); 224 if (errcode < 0) 225 return errcode; 226 227 errcode = fseek(file, begin, SEEK_SET); 228 if (errcode) 229 goto out_unlock; 230 231 read = fread(buffer, 1, size, file); 232 233 errcode = fmap_unlock(mapping); 234 if (errcode < 0) 235 return errcode; 236 237 return (int) read; 238 239 out_unlock: 240 (void) fmap_unlock(mapping); 241 return -pte_nomap; 242 } 243 244 int pt_sec_file_memsize(const struct pt_section *section, uint64_t *size) 245 { 246 if (!section || !size) 247 return -pte_internal; 248 249 if (!section->mapping) 250 return -pte_internal; 251 252 *size = 0ull; 253 254 return 0; 255 } 256