1*74fe6c29SRuslan Bukin /* 2*74fe6c29SRuslan Bukin * Copyright (c) 2013-2018, Intel Corporation 3*74fe6c29SRuslan Bukin * 4*74fe6c29SRuslan Bukin * Redistribution and use in source and binary forms, with or without 5*74fe6c29SRuslan Bukin * modification, are permitted provided that the following conditions are met: 6*74fe6c29SRuslan Bukin * 7*74fe6c29SRuslan Bukin * * Redistributions of source code must retain the above copyright notice, 8*74fe6c29SRuslan Bukin * this list of conditions and the following disclaimer. 9*74fe6c29SRuslan Bukin * * Redistributions in binary form must reproduce the above copyright notice, 10*74fe6c29SRuslan Bukin * this list of conditions and the following disclaimer in the documentation 11*74fe6c29SRuslan Bukin * and/or other materials provided with the distribution. 12*74fe6c29SRuslan Bukin * * Neither the name of Intel Corporation nor the names of its contributors 13*74fe6c29SRuslan Bukin * may be used to endorse or promote products derived from this software 14*74fe6c29SRuslan Bukin * without specific prior written permission. 15*74fe6c29SRuslan Bukin * 16*74fe6c29SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17*74fe6c29SRuslan Bukin * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18*74fe6c29SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19*74fe6c29SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20*74fe6c29SRuslan Bukin * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21*74fe6c29SRuslan Bukin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22*74fe6c29SRuslan Bukin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23*74fe6c29SRuslan Bukin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24*74fe6c29SRuslan Bukin * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25*74fe6c29SRuslan Bukin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26*74fe6c29SRuslan Bukin * POSSIBILITY OF SUCH DAMAGE. 27*74fe6c29SRuslan Bukin */ 28*74fe6c29SRuslan Bukin 29*74fe6c29SRuslan Bukin #include "pt_sync.h" 30*74fe6c29SRuslan Bukin #include "pt_packet.h" 31*74fe6c29SRuslan Bukin #include "pt_opcodes.h" 32*74fe6c29SRuslan Bukin 33*74fe6c29SRuslan Bukin #include "intel-pt.h" 34*74fe6c29SRuslan Bukin 35*74fe6c29SRuslan Bukin 36*74fe6c29SRuslan Bukin /* A psb packet contains a unique 2-byte repeating pattern. 37*74fe6c29SRuslan Bukin * 38*74fe6c29SRuslan Bukin * There are only two ways to fill up a 64bit work with such a pattern. 39*74fe6c29SRuslan Bukin */ 40*74fe6c29SRuslan Bukin static const uint64_t psb_pattern[] = { 41*74fe6c29SRuslan Bukin ((uint64_t) pt_psb_lohi | (uint64_t) pt_psb_lohi << 16 | 42*74fe6c29SRuslan Bukin (uint64_t) pt_psb_lohi << 32 | (uint64_t) pt_psb_lohi << 48), 43*74fe6c29SRuslan Bukin ((uint64_t) pt_psb_hilo | (uint64_t) pt_psb_hilo << 16 | 44*74fe6c29SRuslan Bukin (uint64_t) pt_psb_hilo << 32 | (uint64_t) pt_psb_hilo << 48) 45*74fe6c29SRuslan Bukin }; 46*74fe6c29SRuslan Bukin 47*74fe6c29SRuslan Bukin static const uint8_t *truncate(const uint8_t *pointer, size_t alignment) 48*74fe6c29SRuslan Bukin { 49*74fe6c29SRuslan Bukin uintptr_t raw = (uintptr_t) pointer; 50*74fe6c29SRuslan Bukin 51*74fe6c29SRuslan Bukin raw /= alignment; 52*74fe6c29SRuslan Bukin raw *= alignment; 53*74fe6c29SRuslan Bukin 54*74fe6c29SRuslan Bukin return (const uint8_t *) raw; 55*74fe6c29SRuslan Bukin } 56*74fe6c29SRuslan Bukin 57*74fe6c29SRuslan Bukin static const uint8_t *align(const uint8_t *pointer, size_t alignment) 58*74fe6c29SRuslan Bukin { 59*74fe6c29SRuslan Bukin return truncate(pointer + alignment - 1, alignment); 60*74fe6c29SRuslan Bukin } 61*74fe6c29SRuslan Bukin 62*74fe6c29SRuslan Bukin /* Find a psb packet given a position somewhere in the payload. 63*74fe6c29SRuslan Bukin * 64*74fe6c29SRuslan Bukin * Return the position of the psb packet. 65*74fe6c29SRuslan Bukin * Return NULL, if this is not a psb packet. 66*74fe6c29SRuslan Bukin */ 67*74fe6c29SRuslan Bukin static const uint8_t *pt_find_psb(const uint8_t *pos, 68*74fe6c29SRuslan Bukin const struct pt_config *config) 69*74fe6c29SRuslan Bukin { 70*74fe6c29SRuslan Bukin const uint8_t *begin, *end; 71*74fe6c29SRuslan Bukin int errcode; 72*74fe6c29SRuslan Bukin 73*74fe6c29SRuslan Bukin if (!pos || !config) 74*74fe6c29SRuslan Bukin return NULL; 75*74fe6c29SRuslan Bukin 76*74fe6c29SRuslan Bukin begin = config->begin; 77*74fe6c29SRuslan Bukin end = config->end; 78*74fe6c29SRuslan Bukin 79*74fe6c29SRuslan Bukin /* Navigate to the end of the psb payload pattern. 80*74fe6c29SRuslan Bukin * 81*74fe6c29SRuslan Bukin * Beware that PSB is an extended opcode. We must not confuse the extend 82*74fe6c29SRuslan Bukin * opcode of the following packet as belonging to the PSB. 83*74fe6c29SRuslan Bukin */ 84*74fe6c29SRuslan Bukin if (*pos != pt_psb_hi) 85*74fe6c29SRuslan Bukin pos++; 86*74fe6c29SRuslan Bukin 87*74fe6c29SRuslan Bukin for (; (pos + 1) < end; pos += 2) { 88*74fe6c29SRuslan Bukin uint8_t hi, lo; 89*74fe6c29SRuslan Bukin 90*74fe6c29SRuslan Bukin hi = pos[0]; 91*74fe6c29SRuslan Bukin lo = pos[1]; 92*74fe6c29SRuslan Bukin 93*74fe6c29SRuslan Bukin if (hi != pt_psb_hi) 94*74fe6c29SRuslan Bukin break; 95*74fe6c29SRuslan Bukin 96*74fe6c29SRuslan Bukin if (lo != pt_psb_lo) 97*74fe6c29SRuslan Bukin break; 98*74fe6c29SRuslan Bukin } 99*74fe6c29SRuslan Bukin /* 100*74fe6c29SRuslan Bukin * We're right after the psb payload and within the buffer. 101*74fe6c29SRuslan Bukin * Navigate to the expected beginning of the psb packet. 102*74fe6c29SRuslan Bukin */ 103*74fe6c29SRuslan Bukin pos -= ptps_psb; 104*74fe6c29SRuslan Bukin 105*74fe6c29SRuslan Bukin /* Check if we're still inside the buffer. */ 106*74fe6c29SRuslan Bukin if (pos < begin) 107*74fe6c29SRuslan Bukin return NULL; 108*74fe6c29SRuslan Bukin 109*74fe6c29SRuslan Bukin /* Check that this is indeed a psb packet we're at. */ 110*74fe6c29SRuslan Bukin if (pos[0] != pt_opc_psb || pos[1] != pt_ext_psb) 111*74fe6c29SRuslan Bukin return NULL; 112*74fe6c29SRuslan Bukin 113*74fe6c29SRuslan Bukin errcode = pt_pkt_read_psb(pos, config); 114*74fe6c29SRuslan Bukin if (errcode < 0) 115*74fe6c29SRuslan Bukin return NULL; 116*74fe6c29SRuslan Bukin 117*74fe6c29SRuslan Bukin return pos; 118*74fe6c29SRuslan Bukin } 119*74fe6c29SRuslan Bukin 120*74fe6c29SRuslan Bukin static int pt_sync_within_bounds(const uint8_t *pos, const uint8_t *begin, 121*74fe6c29SRuslan Bukin const uint8_t *end) 122*74fe6c29SRuslan Bukin { 123*74fe6c29SRuslan Bukin /* We allow @pos == @end representing the very end of the trace. 124*74fe6c29SRuslan Bukin * 125*74fe6c29SRuslan Bukin * This will result in -pte_eos when we actually try to read from @pos. 126*74fe6c29SRuslan Bukin */ 127*74fe6c29SRuslan Bukin return (begin <= pos) && (pos <= end); 128*74fe6c29SRuslan Bukin } 129*74fe6c29SRuslan Bukin 130*74fe6c29SRuslan Bukin int pt_sync_set(const uint8_t **sync, const uint8_t *pos, 131*74fe6c29SRuslan Bukin const struct pt_config *config) 132*74fe6c29SRuslan Bukin { 133*74fe6c29SRuslan Bukin const uint8_t *begin, *end; 134*74fe6c29SRuslan Bukin int errcode; 135*74fe6c29SRuslan Bukin 136*74fe6c29SRuslan Bukin if (!sync || !pos || !config) 137*74fe6c29SRuslan Bukin return -pte_internal; 138*74fe6c29SRuslan Bukin 139*74fe6c29SRuslan Bukin begin = config->begin; 140*74fe6c29SRuslan Bukin end = config->end; 141*74fe6c29SRuslan Bukin 142*74fe6c29SRuslan Bukin if (!pt_sync_within_bounds(pos, begin, end)) 143*74fe6c29SRuslan Bukin return -pte_eos; 144*74fe6c29SRuslan Bukin 145*74fe6c29SRuslan Bukin if (end < pos + 2) 146*74fe6c29SRuslan Bukin return -pte_eos; 147*74fe6c29SRuslan Bukin 148*74fe6c29SRuslan Bukin /* Check that this is indeed a psb packet we're at. */ 149*74fe6c29SRuslan Bukin if (pos[0] != pt_opc_psb || pos[1] != pt_ext_psb) 150*74fe6c29SRuslan Bukin return -pte_nosync; 151*74fe6c29SRuslan Bukin 152*74fe6c29SRuslan Bukin errcode = pt_pkt_read_psb(pos, config); 153*74fe6c29SRuslan Bukin if (errcode < 0) 154*74fe6c29SRuslan Bukin return errcode; 155*74fe6c29SRuslan Bukin 156*74fe6c29SRuslan Bukin *sync = pos; 157*74fe6c29SRuslan Bukin 158*74fe6c29SRuslan Bukin return 0; 159*74fe6c29SRuslan Bukin } 160*74fe6c29SRuslan Bukin 161*74fe6c29SRuslan Bukin int pt_sync_forward(const uint8_t **sync, const uint8_t *pos, 162*74fe6c29SRuslan Bukin const struct pt_config *config) 163*74fe6c29SRuslan Bukin { 164*74fe6c29SRuslan Bukin const uint8_t *begin, *end; 165*74fe6c29SRuslan Bukin 166*74fe6c29SRuslan Bukin if (!sync || !pos || !config) 167*74fe6c29SRuslan Bukin return -pte_internal; 168*74fe6c29SRuslan Bukin 169*74fe6c29SRuslan Bukin begin = config->begin; 170*74fe6c29SRuslan Bukin end = config->end; 171*74fe6c29SRuslan Bukin 172*74fe6c29SRuslan Bukin if (!pt_sync_within_bounds(pos, begin, end)) 173*74fe6c29SRuslan Bukin return -pte_internal; 174*74fe6c29SRuslan Bukin 175*74fe6c29SRuslan Bukin /* We search for a full 64bit word. It's OK to skip the current one. */ 176*74fe6c29SRuslan Bukin pos = align(pos, sizeof(*psb_pattern)); 177*74fe6c29SRuslan Bukin 178*74fe6c29SRuslan Bukin /* Search for the psb payload pattern in the buffer. */ 179*74fe6c29SRuslan Bukin for (;;) { 180*74fe6c29SRuslan Bukin const uint8_t *current = pos; 181*74fe6c29SRuslan Bukin uint64_t val; 182*74fe6c29SRuslan Bukin 183*74fe6c29SRuslan Bukin pos += sizeof(uint64_t); 184*74fe6c29SRuslan Bukin if (end < pos) 185*74fe6c29SRuslan Bukin return -pte_eos; 186*74fe6c29SRuslan Bukin 187*74fe6c29SRuslan Bukin val = * (const uint64_t *) current; 188*74fe6c29SRuslan Bukin 189*74fe6c29SRuslan Bukin if ((val != psb_pattern[0]) && (val != psb_pattern[1])) 190*74fe6c29SRuslan Bukin continue; 191*74fe6c29SRuslan Bukin 192*74fe6c29SRuslan Bukin /* We found a 64bit word's worth of psb payload pattern. */ 193*74fe6c29SRuslan Bukin current = pt_find_psb(pos, config); 194*74fe6c29SRuslan Bukin if (!current) 195*74fe6c29SRuslan Bukin continue; 196*74fe6c29SRuslan Bukin 197*74fe6c29SRuslan Bukin *sync = current; 198*74fe6c29SRuslan Bukin return 0; 199*74fe6c29SRuslan Bukin } 200*74fe6c29SRuslan Bukin } 201*74fe6c29SRuslan Bukin 202*74fe6c29SRuslan Bukin int pt_sync_backward(const uint8_t **sync, const uint8_t *pos, 203*74fe6c29SRuslan Bukin const struct pt_config *config) 204*74fe6c29SRuslan Bukin { 205*74fe6c29SRuslan Bukin const uint8_t *begin, *end; 206*74fe6c29SRuslan Bukin 207*74fe6c29SRuslan Bukin if (!sync || !pos || !config) 208*74fe6c29SRuslan Bukin return -pte_internal; 209*74fe6c29SRuslan Bukin 210*74fe6c29SRuslan Bukin begin = config->begin; 211*74fe6c29SRuslan Bukin end = config->end; 212*74fe6c29SRuslan Bukin 213*74fe6c29SRuslan Bukin if (!pt_sync_within_bounds(pos, begin, end)) 214*74fe6c29SRuslan Bukin return -pte_internal; 215*74fe6c29SRuslan Bukin 216*74fe6c29SRuslan Bukin /* We search for a full 64bit word. It's OK to skip the current one. */ 217*74fe6c29SRuslan Bukin pos = truncate(pos, sizeof(*psb_pattern)); 218*74fe6c29SRuslan Bukin 219*74fe6c29SRuslan Bukin /* Search for the psb payload pattern in the buffer. */ 220*74fe6c29SRuslan Bukin for (;;) { 221*74fe6c29SRuslan Bukin const uint8_t *next = pos; 222*74fe6c29SRuslan Bukin uint64_t val; 223*74fe6c29SRuslan Bukin 224*74fe6c29SRuslan Bukin pos -= sizeof(uint64_t); 225*74fe6c29SRuslan Bukin if (pos < begin) 226*74fe6c29SRuslan Bukin return -pte_eos; 227*74fe6c29SRuslan Bukin 228*74fe6c29SRuslan Bukin val = * (const uint64_t *) pos; 229*74fe6c29SRuslan Bukin 230*74fe6c29SRuslan Bukin if ((val != psb_pattern[0]) && (val != psb_pattern[1])) 231*74fe6c29SRuslan Bukin continue; 232*74fe6c29SRuslan Bukin 233*74fe6c29SRuslan Bukin /* We found a 64bit word's worth of psb payload pattern. */ 234*74fe6c29SRuslan Bukin next = pt_find_psb(next, config); 235*74fe6c29SRuslan Bukin if (!next) 236*74fe6c29SRuslan Bukin continue; 237*74fe6c29SRuslan Bukin 238*74fe6c29SRuslan Bukin *sync = next; 239*74fe6c29SRuslan Bukin return 0; 240*74fe6c29SRuslan Bukin } 241*74fe6c29SRuslan Bukin } 242