Index: usr.sbin/pmctrace/pmctrace_pt.h
===================================================================
--- /dev/null
+++ usr.sbin/pmctrace/pmctrace_pt.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2017 Ruslan Bukin
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PMCTRACE_PT_H_
+#define _PMCTRACE_PT_H_
+
+extern struct trace_dev_methods ipt_methods;
+
+#endif /* !_PMCTRACE_PT_H_ */
Index: usr.sbin/pmctrace/pmctrace_pt.c
===================================================================
--- /dev/null
+++ usr.sbin/pmctrace/pmctrace_pt.c
@@ -0,0 +1,387 @@
+/*-
+ * Copyright (c) 2017 Ruslan Bukin
+ * All rights reserved.
+ *
+ * This software was developed by BAE Systems, the University of Cambridge
+ * Computer Laboratory, and Memorial University under DARPA/AFRL contract
+ * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
+ * (TC) research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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
+__FBSDID("$FreeBSD$");
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "pmctrace.h"
+#include "pmctrace_pt.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#define PMCTRACE_PT_DEBUG
+#undef PMCTRACE_PT_DEBUG
+
+#ifdef PMCTRACE_PT_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+static int ipt_flags;
+#define FLAG_BRANCH_TNT (1 << 0) /* Taken/Not Taken */
+
+static struct pmcstat_symbol *
+symbol_lookup(struct mtrace_data *mdata, struct pmcstat_image **image0)
+{
+ struct pmcstat_image *image;
+ struct pmcstat_symbol *sym;
+ struct pmcstat_pcmap *map;
+ uint64_t newpc;
+ uint64_t ip;
+
+ if (mdata->ip & (1UL << 47))
+ ip = mdata->ip | 0xffffUL << 48;
+ else
+ ip = mdata->ip;
+
+ map = pmcstat_process_find_map(mdata->pp, ip);
+ if (map != NULL) {
+ image = map->ppm_image;
+ if (image0 != NULL)
+ *image0 = image;
+ newpc = ip - (map->ppm_lowpc +
+ (image->pi_vaddr - image->pi_start));
+ sym = pmcstat_symbol_search(image, newpc);
+ return (sym);
+ } else
+ dprintf("cpu%d: 0x%lx map not found\n", mdata->cpu, ip);
+
+ return (NULL);
+}
+
+static int
+print_tnt_payload(struct mtrace_data *mdata, uint64_t offset __unused,
+ const struct pt_packet_tnt *packet)
+{
+ char payload[48];
+ uint64_t tnt;
+ uint8_t bits;
+ char *begin;
+ char *end;
+
+ bits = packet->bit_size;
+ tnt = packet->payload;
+ begin = &payload[0];
+ end = begin + bits;
+
+ if (sizeof(payload) < bits)
+ end = begin + sizeof(payload);
+
+ for (; begin < end; ++begin, --bits)
+ *begin = tnt & (1ull << (bits - 1)) ? '!' : '.';
+
+ printf("cpu%d: TNT %s\n", mdata->cpu, payload);
+
+ return (0);
+}
+
+static int
+print_ip_payload(struct mtrace_data *mdata, uint64_t offset __unused,
+ const struct pt_packet_ip *packet)
+{
+ struct pmcstat_image *image;
+ struct pmcstat_symbol *sym;
+
+ switch (packet->ipc) {
+ case pt_ipc_suppressed:
+ break;
+ case pt_ipc_update_16:
+ mdata->ip &= ~0xffffUL;
+ mdata->ip |= (packet->ip & 0xffffUL);
+ break;
+ case pt_ipc_update_32:
+ mdata->ip &= ~0xffffffffUL;
+ mdata->ip |= (packet->ip & 0xffffffffUL);
+ break;
+ case pt_ipc_update_48:
+ mdata->ip &= ~0xffffffffffffUL;
+ mdata->ip |= (packet->ip & 0xffffffffffffUL);
+ break;
+ case pt_ipc_sext_48:
+ mdata->ip &= ~0xffffffffffffUL;
+ mdata->ip |= (packet->ip & 0xffffffffffffUL);
+ symbol_lookup(mdata, NULL);
+ case pt_ipc_full:
+ mdata->ip = packet->ip;
+ break;
+ default:
+ printf("unknown ipc: %d\n", packet->ipc);
+ return (0);
+ }
+
+ sym = symbol_lookup(mdata, &image);
+ if (sym) {
+ printf("cpu%d: IP 0x%lx %s %s\n", mdata->cpu, mdata->ip,
+ pmcstat_string_unintern(image->pi_name),
+ pmcstat_string_unintern(sym->ps_name));
+ } else
+ dprintf("cpu%d: 0x%lx not found\n", mdata->cpu, mdata->ip);
+
+ return (0);
+}
+
+static int
+dump_packets(struct mtrace_data *mdata, struct pt_packet_decoder *decoder,
+ const struct pt_config *config __unused)
+{
+ struct pt_packet packet;
+ uint64_t offset;
+ int error;
+
+ dprintf("%s\n", __func__);
+
+ while (1) {
+ error = pt_pkt_get_offset(decoder, &offset);
+ if (error < 0)
+ errx(EX_SOFTWARE,
+ "ERROR: can't get offset, err %d\n", error);
+
+ error = pt_pkt_next(decoder, &packet, sizeof(packet));
+ if (error < 0) {
+ dprintf("%s: error %d\n", __func__, error);
+ break;
+ }
+
+ switch (packet.type) {
+ case ppt_invalid:
+ case ppt_unknown:
+ case ppt_pad:
+ case ppt_psb:
+ case ppt_psbend:
+ break;
+ case ppt_fup:
+ case ppt_tip:
+ case ppt_tip_pge:
+ case ppt_tip_pgd:
+ print_ip_payload(mdata, offset, &packet.payload.ip);
+ break;
+ case ppt_tnt_8:
+ case ppt_tnt_64:
+ if (ipt_flags & FLAG_BRANCH_TNT)
+ print_tnt_payload(mdata, offset,
+ &packet.payload.tnt);
+ break;
+ case ppt_mode:
+ case ppt_pip:
+ case ppt_vmcs:
+ case ppt_cbr:
+ break;
+ case ppt_tsc:
+ printf("cpu%d: TSC %ld\n", mdata->cpu,
+ packet.payload.tsc.tsc);
+ break;
+ case ppt_tma:
+ break;
+ case ppt_mtc:
+ printf("cpu%d: MTC %x\n", mdata->cpu,
+ packet.payload.mtc.ctc);
+ break;
+ case ppt_cyc:
+ case ppt_stop:
+ case ppt_ovf:
+ case ppt_mnt:
+ case ppt_exstop:
+ case ppt_mwait:
+ case ppt_pwre:
+ case ppt_pwrx:
+ case ppt_ptw:
+ default:
+ break;
+ }
+ }
+
+ return (0);
+}
+
+static int
+ipt_process_chunk(struct mtrace_data *mdata, uint64_t base,
+ uint64_t start, uint64_t end)
+{
+ struct pt_packet_decoder *decoder;
+ struct pt_config config;
+ int error;
+
+ dprintf("%s\n", __func__);
+
+ memset(&config, 0, sizeof(config));
+ pt_config_init(&config);
+
+ error = pt_cpu_read(&config.cpu);
+ if (error < 0)
+ errx(EX_SOFTWARE,
+ "ERROR: pt_cpu_read failed, err %d\n", error);
+ error = pt_cpu_errata(&config.errata, &config.cpu);
+ if (error < 0)
+ errx(EX_SOFTWARE, "ERROR: can't get errata, err %d\n", error);
+
+ config.begin = (uint8_t *)(base + start);
+ config.end = (uint8_t *)(base + end);
+
+ dprintf("%s: begin %lx end %lx\n", __func__,
+ (uint64_t)config.begin, (uint64_t)config.end);
+
+ decoder = pt_pkt_alloc_decoder(&config);
+ if (decoder == NULL) {
+ printf("Can't allocate decoder\n");
+ return (-1);
+ }
+
+ error = pt_pkt_sync_set(decoder, 0ull);
+ if (error < 0)
+ errx(EX_SOFTWARE, "ERROR: sync_set failed, err %d\n", error);
+ error = pt_pkt_sync_forward(decoder);
+ if (error < 0 && error != -pte_eos)
+ errx(EX_SOFTWARE,
+ "ERROR: sync_forward failed, err %d\n", error);
+
+ while (1) {
+ error = dump_packets(mdata, decoder, &config);
+ if (error == 0)
+ break;
+
+ error = pt_pkt_sync_forward(decoder);
+ if (error < 0) {
+ if (error == -pte_eos)
+ return (0);
+ }
+ }
+
+ return (0);
+}
+
+static int
+ipt_process(struct trace_cpu *tc, struct pmcstat_process *pp,
+ uint32_t cpu, uint32_t cycle, uint64_t offset)
+{
+ struct mtrace_data *mdata;
+
+ mdata = &tc->mdata;
+ mdata->pp = pp;
+
+ dprintf("%s: cpu %d, cycle %d, offset %ld\n",
+ __func__, cpu, cycle, offset);
+
+ if (offset == tc->offset)
+ return (0);
+
+ if (cycle == tc->cycle) {
+ if (offset > tc->offset) {
+ ipt_process_chunk(mdata, (uint64_t)tc->base,
+ tc->offset, offset);
+ tc->offset = offset;
+ } else if (offset < tc->offset) {
+ err(EXIT_FAILURE,
+ "cpu%d: offset already processed %lx %lx",
+ cpu, offset, tc->offset);
+ }
+ } else if (cycle > tc->cycle) {
+ if ((cycle - tc->cycle) > 1)
+ err(EXIT_FAILURE,
+ "cpu%d: trace buffers fills up faster than"
+ " we can process it (%d/%d). Consider setting"
+ " trace filters",
+ cpu, cycle, tc->cycle);
+ ipt_process_chunk(mdata, (uint64_t)tc->base,
+ tc->offset, tc->bufsize);
+ tc->offset = 0;
+ tc->cycle += 1;
+ ipt_process_chunk(mdata, (uint64_t)tc->base,
+ tc->offset, offset);
+ tc->offset = offset;
+ }
+
+ return (0);
+}
+
+static int
+ipt_option(int option)
+{
+
+ switch (option) {
+ case 't':
+ /* Decode 'Taken/Not_Taken branch' packet. */
+ ipt_flags |= FLAG_BRANCH_TNT;
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+struct trace_dev_methods ipt_methods = {
+ .process = ipt_process,
+ .option = ipt_option,
+};