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_sync.h" 30 #include "pt_packet.h" 31 #include "pt_opcodes.h" 32 33 #include "intel-pt.h" 34 35 36 /* A psb packet contains a unique 2-byte repeating pattern. 37 * 38 * There are only two ways to fill up a 64bit work with such a pattern. 39 */ 40 static const uint64_t psb_pattern[] = { 41 ((uint64_t) pt_psb_lohi | (uint64_t) pt_psb_lohi << 16 | 42 (uint64_t) pt_psb_lohi << 32 | (uint64_t) pt_psb_lohi << 48), 43 ((uint64_t) pt_psb_hilo | (uint64_t) pt_psb_hilo << 16 | 44 (uint64_t) pt_psb_hilo << 32 | (uint64_t) pt_psb_hilo << 48) 45 }; 46 47 static const uint8_t *truncate(const uint8_t *pointer, size_t alignment) 48 { 49 uintptr_t raw = (uintptr_t) pointer; 50 51 raw /= alignment; 52 raw *= alignment; 53 54 return (const uint8_t *) raw; 55 } 56 57 static const uint8_t *align(const uint8_t *pointer, size_t alignment) 58 { 59 return truncate(pointer + alignment - 1, alignment); 60 } 61 62 /* Find a psb packet given a position somewhere in the payload. 63 * 64 * Return the position of the psb packet. 65 * Return NULL, if this is not a psb packet. 66 */ 67 static const uint8_t *pt_find_psb(const uint8_t *pos, 68 const struct pt_config *config) 69 { 70 const uint8_t *begin, *end; 71 int errcode; 72 73 if (!pos || !config) 74 return NULL; 75 76 begin = config->begin; 77 end = config->end; 78 79 /* Navigate to the end of the psb payload pattern. 80 * 81 * Beware that PSB is an extended opcode. We must not confuse the extend 82 * opcode of the following packet as belonging to the PSB. 83 */ 84 if (*pos != pt_psb_hi) 85 pos++; 86 87 for (; (pos + 1) < end; pos += 2) { 88 uint8_t hi, lo; 89 90 hi = pos[0]; 91 lo = pos[1]; 92 93 if (hi != pt_psb_hi) 94 break; 95 96 if (lo != pt_psb_lo) 97 break; 98 } 99 /* 100 * We're right after the psb payload and within the buffer. 101 * Navigate to the expected beginning of the psb packet. 102 */ 103 pos -= ptps_psb; 104 105 /* Check if we're still inside the buffer. */ 106 if (pos < begin) 107 return NULL; 108 109 /* Check that this is indeed a psb packet we're at. */ 110 if (pos[0] != pt_opc_psb || pos[1] != pt_ext_psb) 111 return NULL; 112 113 errcode = pt_pkt_read_psb(pos, config); 114 if (errcode < 0) 115 return NULL; 116 117 return pos; 118 } 119 120 static int pt_sync_within_bounds(const uint8_t *pos, const uint8_t *begin, 121 const uint8_t *end) 122 { 123 /* We allow @pos == @end representing the very end of the trace. 124 * 125 * This will result in -pte_eos when we actually try to read from @pos. 126 */ 127 return (begin <= pos) && (pos <= end); 128 } 129 130 int pt_sync_set(const uint8_t **sync, const uint8_t *pos, 131 const struct pt_config *config) 132 { 133 const uint8_t *begin, *end; 134 int errcode; 135 136 if (!sync || !pos || !config) 137 return -pte_internal; 138 139 begin = config->begin; 140 end = config->end; 141 142 if (!pt_sync_within_bounds(pos, begin, end)) 143 return -pte_eos; 144 145 if (end < pos + 2) 146 return -pte_eos; 147 148 /* Check that this is indeed a psb packet we're at. */ 149 if (pos[0] != pt_opc_psb || pos[1] != pt_ext_psb) 150 return -pte_nosync; 151 152 errcode = pt_pkt_read_psb(pos, config); 153 if (errcode < 0) 154 return errcode; 155 156 *sync = pos; 157 158 return 0; 159 } 160 161 int pt_sync_forward(const uint8_t **sync, const uint8_t *pos, 162 const struct pt_config *config) 163 { 164 const uint8_t *begin, *end, *start; 165 166 if (!sync || !pos || !config) 167 return -pte_internal; 168 169 start = pos; 170 begin = config->begin; 171 end = config->end; 172 173 if (!pt_sync_within_bounds(pos, begin, end)) 174 return -pte_internal; 175 176 /* We search for a full 64bit word. It's OK to skip the current one. */ 177 pos = align(pos, sizeof(*psb_pattern)); 178 179 /* Search for the psb payload pattern in the buffer. */ 180 for (;;) { 181 const uint8_t *current = pos; 182 uint64_t val; 183 184 pos += sizeof(uint64_t); 185 if (end < pos) 186 return -pte_eos; 187 188 val = * (const uint64_t *) current; 189 190 if ((val != psb_pattern[0]) && (val != psb_pattern[1])) 191 continue; 192 193 /* We found a 64bit word's worth of psb payload pattern. */ 194 current = pt_find_psb(pos, config); 195 if (!current) 196 continue; 197 198 /* If @start points inside a PSB, we may find that one. Ignore 199 * it unless @start points to its beginning. 200 */ 201 if (current < start) 202 continue; 203 204 *sync = current; 205 return 0; 206 } 207 } 208 209 int pt_sync_backward(const uint8_t **sync, const uint8_t *pos, 210 const struct pt_config *config) 211 { 212 const uint8_t *begin, *end; 213 214 if (!sync || !pos || !config) 215 return -pte_internal; 216 217 begin = config->begin; 218 end = config->end; 219 220 if (!pt_sync_within_bounds(pos, begin, end)) 221 return -pte_internal; 222 223 /* We search for a full 64bit word. It's OK to skip the current one. */ 224 pos = truncate(pos, sizeof(*psb_pattern)); 225 226 /* Search for the psb payload pattern in the buffer. */ 227 for (;;) { 228 const uint8_t *next = pos; 229 uint64_t val; 230 231 pos -= sizeof(uint64_t); 232 if (pos < begin) 233 return -pte_eos; 234 235 val = * (const uint64_t *) pos; 236 237 if ((val != psb_pattern[0]) && (val != psb_pattern[1])) 238 continue; 239 240 /* We found a 64bit word's worth of psb payload pattern. */ 241 next = pt_find_psb(next, config); 242 if (!next) 243 continue; 244 245 *sync = next; 246 return 0; 247 } 248 } 249