|
Packit |
b1f7ae |
/*
|
|
Packit |
b1f7ae |
* Copyright (c) 2013-2017, Intel Corporation
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
b1f7ae |
* modification, are permitted provided that the following conditions are met:
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* * Redistributions of source code must retain the above copyright notice,
|
|
Packit |
b1f7ae |
* this list of conditions and the following disclaimer.
|
|
Packit |
b1f7ae |
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
Packit |
b1f7ae |
* this list of conditions and the following disclaimer in the documentation
|
|
Packit |
b1f7ae |
* and/or other materials provided with the distribution.
|
|
Packit |
b1f7ae |
* * Neither the name of Intel Corporation nor the names of its contributors
|
|
Packit |
b1f7ae |
* may be used to endorse or promote products derived from this software
|
|
Packit |
b1f7ae |
* without specific prior written permission.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
Packit |
b1f7ae |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit |
b1f7ae |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
Packit |
b1f7ae |
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
Packit |
b1f7ae |
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
Packit |
b1f7ae |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
Packit |
b1f7ae |
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
Packit |
b1f7ae |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
Packit |
b1f7ae |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
Packit |
b1f7ae |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
Packit |
b1f7ae |
* POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#include "pt_sync.h"
|
|
Packit |
b1f7ae |
#include "pt_packet.h"
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#include "intel-pt.h"
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* A psb packet contains a unique 2-byte repeating pattern.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* There are only two ways to fill up a 64bit work with such a pattern.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
const uint64_t psb_pattern[] = {
|
|
Packit |
b1f7ae |
((uint64_t) pt_psb_lohi | (uint64_t) pt_psb_lohi << 16 |
|
|
Packit |
b1f7ae |
(uint64_t) pt_psb_lohi << 32 | (uint64_t) pt_psb_lohi << 48),
|
|
Packit |
b1f7ae |
((uint64_t) pt_psb_hilo | (uint64_t) pt_psb_hilo << 16 |
|
|
Packit |
b1f7ae |
(uint64_t) pt_psb_hilo << 32 | (uint64_t) pt_psb_hilo << 48)
|
|
Packit |
b1f7ae |
};
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static const uint8_t *truncate(const uint8_t *pointer, size_t alignment)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uintptr_t raw = (uintptr_t) pointer;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
raw /= alignment;
|
|
Packit |
b1f7ae |
raw *= alignment;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return (const uint8_t *) raw;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static const uint8_t *align(const uint8_t *pointer, size_t alignment)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
return truncate(pointer + alignment - 1, alignment);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Find a psb packet given a position somewhere in the payload.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* Return the position of the psb packet.
|
|
Packit |
b1f7ae |
* Return NULL, if this is not a psb packet.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
static const uint8_t *pt_find_psb(const uint8_t *pos,
|
|
Packit |
b1f7ae |
const struct pt_config *config)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
const uint8_t *begin, *end;
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!pos || !config)
|
|
Packit |
b1f7ae |
return NULL;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
begin = config->begin;
|
|
Packit |
b1f7ae |
end = config->end;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Navigate to the end of the psb payload pattern.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* Beware that PSB is an extended opcode. We must not confuse the extend
|
|
Packit |
b1f7ae |
* opcode of the following packet as belonging to the PSB.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
if (*pos != pt_psb_hi)
|
|
Packit |
b1f7ae |
pos++;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
for (; (pos + 1) < end; pos += 2) {
|
|
Packit |
b1f7ae |
uint8_t hi, lo;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
hi = pos[0];
|
|
Packit |
b1f7ae |
lo = pos[1];
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (hi != pt_psb_hi)
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (lo != pt_psb_lo)
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
/*
|
|
Packit |
b1f7ae |
* We're right after the psb payload and within the buffer.
|
|
Packit |
b1f7ae |
* Navigate to the expected beginning of the psb packet.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
pos -= ptps_psb;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Check if we're still inside the buffer. */
|
|
Packit |
b1f7ae |
if (pos < begin)
|
|
Packit |
b1f7ae |
return NULL;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Check that this is indeed a psb packet we're at. */
|
|
Packit |
b1f7ae |
if (pos[0] != pt_opc_psb || pos[1] != pt_ext_psb)
|
|
Packit |
b1f7ae |
return NULL;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_pkt_read_psb(pos, config);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return NULL;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return pos;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int pt_sync_within_bounds(const uint8_t *pos, const uint8_t *begin,
|
|
Packit |
b1f7ae |
const uint8_t *end)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
/* We allow @pos == @end representing the very end of the trace.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* This will result in -pte_eos when we actually try to read from @pos.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
return (begin <= pos) && (pos <= end);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int pt_sync_set(const uint8_t **sync, const uint8_t *pos,
|
|
Packit |
b1f7ae |
const struct pt_config *config)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
const uint8_t *begin, *end;
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!sync || !pos || !config)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
begin = config->begin;
|
|
Packit |
b1f7ae |
end = config->end;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!pt_sync_within_bounds(pos, begin, end))
|
|
Packit |
b1f7ae |
return -pte_eos;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (end < pos + 2)
|
|
Packit |
b1f7ae |
return -pte_eos;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Check that this is indeed a psb packet we're at. */
|
|
Packit |
b1f7ae |
if (pos[0] != pt_opc_psb || pos[1] != pt_ext_psb)
|
|
Packit |
b1f7ae |
return -pte_nosync;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_pkt_read_psb(pos, config);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*sync = pos;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int pt_sync_forward(const uint8_t **sync, const uint8_t *pos,
|
|
Packit |
b1f7ae |
const struct pt_config *config)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
const uint8_t *begin, *end;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!sync || !pos || !config)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
begin = config->begin;
|
|
Packit |
b1f7ae |
end = config->end;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!pt_sync_within_bounds(pos, begin, end))
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We search for a full 64bit word. It's OK to skip the current one. */
|
|
Packit |
b1f7ae |
pos = align(pos, sizeof(*psb_pattern));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Search for the psb payload pattern in the buffer. */
|
|
Packit |
b1f7ae |
for (;;) {
|
|
Packit |
b1f7ae |
const uint8_t *current = pos;
|
|
Packit |
b1f7ae |
uint64_t val;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
pos += sizeof(uint64_t);
|
|
Packit |
b1f7ae |
if (end < pos)
|
|
Packit |
b1f7ae |
return -pte_eos;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
val = * (const uint64_t *) current;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if ((val != psb_pattern[0]) && (val != psb_pattern[1]))
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We found a 64bit word's worth of psb payload pattern. */
|
|
Packit |
b1f7ae |
current = pt_find_psb(pos, config);
|
|
Packit |
b1f7ae |
if (!current)
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*sync = current;
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int pt_sync_backward(const uint8_t **sync, const uint8_t *pos,
|
|
Packit |
b1f7ae |
const struct pt_config *config)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
const uint8_t *begin, *end;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!sync || !pos || !config)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
begin = config->begin;
|
|
Packit |
b1f7ae |
end = config->end;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!pt_sync_within_bounds(pos, begin, end))
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We search for a full 64bit word. It's OK to skip the current one. */
|
|
Packit |
b1f7ae |
pos = truncate(pos, sizeof(*psb_pattern));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Search for the psb payload pattern in the buffer. */
|
|
Packit |
b1f7ae |
for (;;) {
|
|
Packit |
b1f7ae |
const uint8_t *next = pos;
|
|
Packit |
b1f7ae |
uint64_t val;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
pos -= sizeof(uint64_t);
|
|
Packit |
b1f7ae |
if (pos < begin)
|
|
Packit |
b1f7ae |
return -pte_eos;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
val = * (const uint64_t *) pos;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if ((val != psb_pattern[0]) && (val != psb_pattern[1]))
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We found a 64bit word's worth of psb payload pattern. */
|
|
Packit |
b1f7ae |
next = pt_find_psb(next, config);
|
|
Packit |
b1f7ae |
if (!next)
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*sync = next;
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|