Blame libipt/src/pt_sync.c

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
}