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