Page MenuHomeFreeBSD

D40728.id125098.diff
No OneTemporary

D40728.id125098.diff

Index: usr.sbin/Makefile.aarch64
===================================================================
--- usr.sbin/Makefile.aarch64
+++ usr.sbin/Makefile.aarch64
@@ -4,3 +4,4 @@
SUBDIR+= acpi
.endif
SUBDIR+= ofwdump
+SUBDIR+= hwt
Index: usr.sbin/hwt/Makefile
===================================================================
--- /dev/null
+++ usr.sbin/hwt/Makefile
@@ -0,0 +1,21 @@
+# $FreeBSD$
+
+PROG_CXX= hwt
+MAN=
+
+CFLAGS+= -I${SRCTOP}/lib/libpmcstat
+
+LIBADD= elf pmcstat
+
+SRCS= hwt.c \
+ hwt_elf.c \
+ hwt_process.c \
+ hwt_record.c \
+ libpmcstat_stubs.c
+
+.if ${MACHINE_CPUARCH} == "aarch64"
+SRCS+= hwt_coresight.c
+LIBADD+= opencsd
+.endif
+
+.include <bsd.prog.mk>
Index: usr.sbin/hwt/hwt.c
===================================================================
--- /dev/null
+++ usr.sbin/hwt/hwt.c
@@ -0,0 +1,590 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * 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 <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/errno.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/cpuset.h>
+#include <sys/hwt.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <err.h>
+#include <sysexits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+
+#include "libpmcstat_stubs.h"
+#include <libpmcstat.h>
+
+#include "hwtvar.h"
+
+#if defined(__aarch64__)
+#include "hwt_coresight.h"
+#endif
+
+#define PARENTSOCKET 0
+#define CHILDSOCKET 1
+#define NSOCKPAIRFD 2
+
+static struct trace_context tcs;
+
+static struct trace_dev trace_devs[] = {
+#if defined(__aarch64__)
+ { "coresight", "ARM Coresight", &cs_methods },
+#endif
+ { NULL, NULL, NULL }
+};
+
+void
+hwt_sleep(void)
+{
+ struct timespec time_to_sleep;
+
+ time_to_sleep.tv_sec = 0;
+ time_to_sleep.tv_nsec = 10000000; /* 10 ms */
+
+ nanosleep(&time_to_sleep, &time_to_sleep);
+}
+
+void
+hwt_procexit(pid_t pid, int exit_status __unused)
+{
+ struct trace_context *tc;
+
+ tc = &tcs;
+
+ if (tc->pid == pid)
+ tc->terminate = 1;
+}
+
+static int
+hwt_unsuspend_proc(struct trace_context *tc)
+{
+ struct hwt_wakeup w;
+ int error;
+
+ error = ioctl(tc->thr_fd, HWT_IOC_WAKEUP, &w);
+
+ return (error);
+}
+
+int
+hwt_mmap_received(struct trace_context *tc,
+ struct hwt_record_user_entry *entry __unused)
+{
+ int error;
+
+ assert(tc->mode == HWT_MODE_THREAD);
+
+ if (!tc->suspend_on_mmap)
+ return (0);
+
+ if (tc->func_name == NULL)
+ return (0);
+
+ error = hwt_find_sym(tc);
+ if (error != 0) {
+ hwt_unsuspend_proc(tc);
+ return (-1);
+ }
+
+ tc->suspend_on_mmap = 0;
+
+ error = tc->trace_dev->methods->set_config(tc);
+ if (error)
+ return (-2);
+
+ error = hwt_start_tracing(tc);
+ if (error)
+ return (-2);
+
+ printf("%s: tracing started\n", __func__);
+
+ hwt_unsuspend_proc(tc);
+
+ return (0);
+}
+
+static int
+hwt_ctx_alloc(struct trace_context *tc)
+{
+ struct hwt_alloc al;
+ cpuset_t cpu_map;
+ int error;
+
+ CPU_ZERO(&cpu_map);
+
+ memset(&al, 0, sizeof(struct hwt_alloc));
+
+ al.mode = tc->mode;
+ if (tc->mode == HWT_MODE_THREAD)
+ al.pid = tc->pid;
+ else {
+ CPU_SET(tc->cpu, &cpu_map);
+ al.cpu_map = cpu_map;
+ }
+
+ al.bufsize = tc->bufsize;
+ al.backend_name = tc->trace_dev->name;
+ al.ident = &tc->ident;
+
+ error = ioctl(tc->fd, HWT_IOC_ALLOC, &al);
+
+ return (error);
+}
+
+static int
+hwt_map_memory(struct trace_context *tc, int tid)
+{
+ char filename[32];
+
+ if (tc->mode == HWT_MODE_THREAD)
+ sprintf(filename, "/dev/hwt_%d_%d", tc->ident, tid);
+ else
+ sprintf(filename, "/dev/hwt_%d_%d", tc->ident, tc->cpu);
+
+ tc->thr_fd = open(filename, O_RDONLY);
+ if (tc->thr_fd < 0) {
+ printf("Can't open %s\n", filename);
+ return (-1);
+ }
+
+ tc->base = mmap(NULL, tc->bufsize, PROT_READ, MAP_SHARED, tc->thr_fd,
+ 0);
+ if (tc->base == MAP_FAILED) {
+ printf("mmap failed: err %d\n", errno);
+ return (-1);
+ }
+
+ printf("%s: tc->base %#p\n", __func__, tc->base);
+
+ return (0);
+}
+
+static int __unused
+hwt_ncpu(void)
+{
+ int ncpu;
+
+ ncpu = sysconf(_SC_NPROCESSORS_CONF);
+
+ return (ncpu);
+}
+
+int
+hwt_get_offs(struct trace_context *tc, size_t *offs)
+{
+ struct hwt_bufptr_get bget;
+ vm_offset_t curpage_offset;
+ int curpage;
+ int error;
+
+ bget.curpage = &curpage;
+ bget.curpage_offset = &curpage_offset;
+
+ error = ioctl(tc->thr_fd, HWT_IOC_BUFPTR_GET, &bget);
+ if (error)
+ return (error);
+
+#if 0
+ printf("curpage %ld curpage_offset %ld\n", curpage, curpage_offset);
+#endif
+
+ *offs = curpage * PAGE_SIZE + curpage_offset;
+
+ return (0);
+}
+
+static int
+hwt_get_records(struct trace_context *tc, uint32_t *nrec)
+{
+ int nrecords;
+ int error;
+
+ error = hwt_record_fetch(tc, &nrecords);
+ if (error)
+ return (error);
+
+ *nrec = nrecords;
+
+ return (0);
+}
+
+int
+hwt_find_sym(struct trace_context *tc)
+{
+ struct pmcstat_symbol *sym;
+ uintptr_t addr_start;
+ uintptr_t addr_end;
+
+ sym = pmcstat_symbol_search_by_name(tc->pp, tc->image_name,
+ tc->func_name, &addr_start, &addr_end);
+ if (sym) {
+ printf("sym found, start end %lx %lx\n", (uint64_t)addr_start,
+ (uint64_t)addr_end);
+ tc->addr_ranges[tc->nranges] = addr_start;
+ tc->addr_ranges[tc->nranges + 1] = addr_end;
+ tc->nranges += 1;
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
+int
+hwt_start_tracing(struct trace_context *tc)
+{
+ struct hwt_start s;
+ int error;
+
+ error = ioctl(tc->thr_fd, HWT_IOC_START, &s);
+
+ return (error);
+}
+
+static void
+usage(void)
+{
+
+ errx(EX_USAGE,
+ "hwt [-s cpu_id] [-c devname] [-b bufsize] [-t id] [-r] [-w file] [-i name]"
+ " [-f name] [path to executable]\n"
+ "\t -s\tcpu_id\t\tCPU (kernel) mode\n"
+ "\t -c\tname\t\tName of tracing device, e.g. coresight\n"
+ "\t -b\tbufsize\t\tSize of trace buffer (per each thread) in bytes.\n"
+ "\t -t\tid\t\tThread index of application passed to decoder\n"
+ "\t -r\t\t\tRaw flag. Do not decode results\n"
+ "\t -w\tfilename\tStore results into file\n"
+ "\t -i\tname\t\tfilter by dynamic library / executable name or 'kernel' \n"
+ "\t -f\tname\t\tfilter by function name\n"
+
+#if defined(__aarch64__)
+#endif
+ );
+}
+
+static int
+hwt_mode_cpu(struct trace_context *tc)
+{
+ int error;
+
+ if (tc->image_name == NULL || tc->func_name == NULL)
+ errx(EX_USAGE, "IP range filtering must be setup for CPU"
+ " tracing");
+
+ error = hwt_ctx_alloc(tc);
+ if (error) {
+ printf("%s: failed to alloc kernel-mode ctx, error %d\n",
+ __func__, error);
+ return (error);
+ }
+
+ error = hwt_map_memory(tc, 0);
+ if (error != 0) {
+ printf("can't map memory");
+ return (error);
+ }
+
+ tc->pp->pp_pid = -1;
+
+ uint32_t nrec;
+ int tot_rec;
+ int nlibs;
+
+ nlibs = 1;
+ tot_rec = 0;
+
+ do {
+ error = hwt_get_records(tc, &nrec);
+ if (error != 0)
+ return (error);
+ tot_rec += nrec;
+ hwt_sleep();
+ } while (tot_rec < nlibs);
+
+ error = hwt_find_sym(tc);
+ if (error)
+ errx(EX_USAGE, "could not find symbol");
+
+ error = tc->trace_dev->methods->set_config(tc);
+ if (error != 0)
+ errx(EX_DATAERR, "can't set config");
+
+ error = hwt_start_tracing(tc);
+ if (error)
+ errx(EX_SOFTWARE, "failed to start tracing, error %d\n", error);
+
+#if 0
+ size_t offs;
+ while (1) {
+ hwt_get_offs(tc, &offs);
+ printf("new offs %lx\n", offs);
+ sleep(1);
+ }
+#endif
+
+ error = tc->trace_dev->methods->process(tc);
+ if (error) {
+ printf("cant process data, error %d\n", error);
+ return (error);
+ }
+
+ return (0);
+}
+
+static int
+hwt_mode_thread(struct trace_context *tc, char **cmd, char **env)
+{
+ struct stat st;
+ uint32_t tot_rec;
+ uint32_t nrec;
+ uint32_t nlibs;
+ int sockpair[NSOCKPAIRFD];
+ int error;
+
+ if (tc->func_name != NULL)
+ tc->suspend_on_mmap = 1;
+
+ error = stat(*cmd, &st);
+ if (error) {
+ printf("Could not find target executable, error %d.\n", error);
+ return (error);
+ }
+
+ error = hwt_elf_count_libs(*cmd, &nlibs);
+ if (error != 0) {
+ printf("could not count libs\n");
+ return (error);
+ }
+
+ nlibs += 1; /* add binary itself. */
+
+ printf("cmd is %s, nlibs %d\n", *cmd, nlibs);
+
+ error = hwt_process_create(sockpair, cmd, env, &tc->pid);
+ if (error != 0)
+ return (error);
+
+ printf("%s: process pid %d created\n", __func__, tc->pid);
+
+ tc->pp->pp_pid = tc->pid;
+
+ error = hwt_ctx_alloc(tc);
+ if (error) {
+ printf("%s: failed to alloc ctx, pid %d error %d\n", __func__,
+ tc->pid, error);
+ return (error);
+ }
+
+ error = hwt_map_memory(tc, 0);
+ if (error != 0) {
+ printf("can't map memory");
+ return (error);
+ }
+
+ error = tc->trace_dev->methods->set_config(tc);
+ if (error != 0)
+ errx(EX_DATAERR, "can't set config");
+
+ if (tc->func_name == NULL) {
+ /* No address range filtering. Start tracing immediately. */
+ error = hwt_start_tracing(tc);
+ if (error)
+ errx(EX_SOFTWARE, "failed to start tracing, error %d\n",
+ error);
+ }
+
+ error = hwt_process_start(sockpair);
+ if (error != 0)
+ return (error);
+
+ printf("nlibs %d\n", nlibs);
+
+ tot_rec = 0;
+
+ /*
+ * Ensure we got expected amount of mmap/interp records so that
+ * mapping tables constructed before we do symbol lookup.
+ */
+
+ do {
+ error = hwt_get_records(tc, &nrec);
+ if (error != 0)
+ return (error);
+ tot_rec += nrec;
+ hwt_sleep();
+ } while (tot_rec < nlibs);
+
+ error = tc->trace_dev->methods->process(tc);
+ if (error) {
+ printf("cant process data, error %d\n", error);
+ return (error);
+ }
+
+ return (0);
+}
+
+int
+main(int argc, char **argv, char **env)
+{
+ struct trace_context *tc;
+ char *trace_dev_name;
+ int error;
+ int option;
+ int i;
+ int found;
+
+ tc = &tcs;
+
+ memset(tc, 0, sizeof(struct trace_context));
+
+ /* Defaults */
+ tc->bufsize = 128 * 1024 * 1024;
+
+ /* First available is default trace device. */
+ tc->trace_dev = &trace_devs[0];
+ if (tc->trace_dev->name == NULL) {
+ printf("No trace devices available\n");
+ return (1);
+ }
+
+ tc->mode = HWT_MODE_THREAD;
+
+ while ((option = getopt(argc, argv, "s:hc:b:rw:t:i:f:")) != -1)
+ switch (option) {
+ case 's':
+ tc->mode = HWT_MODE_CPU;
+ tc->cpu = atoi(optarg);
+ break;
+ case 'c':
+ trace_dev_name = strdup(optarg);
+ found = 0;
+ for (i = 0; trace_devs[i].name != NULL; i++) {
+ if (strcmp(trace_devs[i].name,
+ trace_dev_name) == 0) {
+ tc->trace_dev = &trace_devs[i];
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ printf("Trace device \"%s\" not available.\n",
+ trace_dev_name);
+ return (ENOENT);
+ }
+ break;
+ case 'b':
+ tc->bufsize = atol(optarg);
+ break;
+ case 'r':
+ /* Do not decode trace. */
+ tc->raw = 1;
+ break;
+ case 'w':
+ /* Store trace into a file. */
+ tc->filename = strdup(optarg);
+ break;
+ case 'i':
+ /*
+ * Name of dynamic lib or main executable for IP
+ * address range filtering.
+ */
+ tc->image_name = strdup(optarg);
+ break;
+ case 'f':
+ /* Name of the func to trace. */
+ tc->func_name = strdup(optarg);
+ break;
+ case 't':
+ tc->thread_id = atoi(optarg);
+ break;
+ case 'h':
+ usage();
+ break;
+ default:
+ break;
+ }
+
+ if (tc->raw != 0 && tc->filename == NULL) {
+ printf("Filename must be specified for the raw data.\n");
+ exit(1);
+ }
+
+ if (tc->filename != NULL) {
+ tc->f = fopen(tc->filename, "w");
+ if (tc->f == NULL) {
+ printf("could not open file %s\n", tc->filename);
+ return (ENXIO);
+ }
+ }
+
+ if ((tc->image_name == NULL && tc->func_name != NULL) ||
+ (tc->image_name != NULL && tc->func_name == NULL))
+ errx(EX_USAGE, "For address range tracing specify both image "
+ "and func, or none of them.");
+
+ tc->fd = open("/dev/hwt", O_RDWR);
+ if (tc->fd < 0) {
+ printf("Can't open /dev/hwt\n");
+ return (-1);
+ }
+
+ tc->pp = hwt_process_alloc();
+ tc->pp->pp_isactive = 1;
+
+ argc += optind;
+ argv += optind;
+
+ if (tc->mode == HWT_MODE_THREAD) {
+ if (*argv == NULL)
+ usage();
+ error = hwt_mode_thread(tc, argv, env);
+ } else {
+ if (*argv != NULL)
+ usage();
+ error = hwt_mode_cpu(tc);
+ }
+
+ close(tc->fd);
+
+ if (tc->filename)
+ fclose(tc->f);
+
+ return (error);
+}
Index: usr.sbin/hwt/hwt_coresight.h
===================================================================
--- /dev/null
+++ usr.sbin/hwt/hwt_coresight.h
@@ -0,0 +1,284 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * 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.
+ */
+
+#ifndef _HWT_CORESIGHT_H_
+#define _HWT_CORESIGHT_H_
+
+#define TRCPRGCTLR 0x004 /* Trace Programming Control Register */
+#define TRCPRGCTLR_EN (1 << 0) /* Trace unit enable bit */
+#define TRCPROCSELR 0x008 /* Trace PE Select Control Register */
+#define TRCSTATR 0x00C /* Trace Trace Status Register */
+#define TRCSTATR_PMSTABLE (1 << 1) /* The programmers' model is stable. */
+#define TRCSTATR_IDLE (1 << 0) /* The trace unit is idle. */
+#define TRCCONFIGR 0x010 /* Trace Trace Configuration Register */
+#define TRCCONFIGR_DV (1 << 17) /* Data value tracing is enabled when INSTP0 is not 0b00 */
+#define TRCCONFIGR_DA (1 << 16) /* Data address tracing is enabled when INSTP0 is not 0b00. */
+#define TRCCONFIGR_VMIDOPT (1 << 15) /* Control bit to configure the Virtual context identifier value */
+#define TRCCONFIGR_QE_S 13 /* Q element enable field */
+#define TRCCONFIGR_QE_M (0x3 << TRCCONFIGR_QE_S)
+#define TRCCONFIGR_RS (1 << 12) /* Return stack enable bit */
+#define TRCCONFIGR_TS (1 << 11) /* Global timestamp tracing is enabled. */
+#define TRCCONFIGR_COND_S 8 /* Conditional instruction tracing bit. */
+#define TRCCONFIGR_COND_M (0x7 << TRCCONFIGR_COND_S)
+#define TRCCONFIGR_COND_DIS 0
+#define TRCCONFIGR_COND_LDR (1 << TRCCONFIGR_COND_S) /* Conditional load instructions are traced. */
+#define TRCCONFIGR_COND_STR (2 << TRCCONFIGR_COND_S) /* Conditional store instructions are traced. */
+#define TRCCONFIGR_COND_LDRSTR (3 << TRCCONFIGR_COND_S) /* Conditional load and store instructions are traced. */
+#define TRCCONFIGR_COND_ALL (7 << TRCCONFIGR_COND_S) /* All conditional instructions are traced. */
+#define TRCCONFIGR_VMID (1 << 7) /* Virtual context identifier tracing is enabled. */
+#define TRCCONFIGR_CID (1 << 6) /* Context ID tracing is enabled. */
+#define TRCCONFIGR_CCI (1 << 4) /* Cycle counting in the instruction trace is enabled. */
+#define TRCCONFIGR_BB (1 << 3) /* Branch broadcast mode is enabled. */
+#define TRCCONFIGR_INSTP0_S 1 /* Instruction P0 field. */
+#define TRCCONFIGR_INSTP0_M (0x3 << TRCCONFIGR_INSTP0_S)
+#define TRCCONFIGR_INSTP0_NONE 0 /* Do not trace load and store instructions as P0 instructions. */
+#define TRCCONFIGR_INSTP0_LDR (1 << TRCCONFIGR_INSTP0_S) /* Trace load instructions as P0 instructions. */
+#define TRCCONFIGR_INSTP0_STR (2 << TRCCONFIGR_INSTP0_S) /* Trace store instructions as P0 instructions. */
+#define TRCCONFIGR_INSTP0_LDRSTR (3 << TRCCONFIGR_INSTP0_S) /* Trace load and store instructions as P0 instr. */
+#define TRCAUXCTLR 0x018 /* Trace Auxiliary Control Register */
+#define TRCEVENTCTL0R 0x020 /* Trace Event Control 0 Register */
+#define TRCEVENTCTL1R 0x024 /* Trace Event Control 1 Register */
+#define TRCSTALLCTLR 0x02C /* Trace Stall Control Register */
+#define TRCTSCTLR 0x030 /* Trace Global Timestamp Control Register */
+#define TRCSYNCPR 0x034 /* Trace Synchronization Period Register */
+#define TRCSYNCPR_PERIOD_S 0
+#define TRCSYNCPR_PERIOD_M 0x1f
+#define TRCSYNCPR_1K (10 << TRCSYNCPR_PERIOD_S)
+#define TRCSYNCPR_2K (11 << TRCSYNCPR_PERIOD_S)
+#define TRCSYNCPR_4K (12 << TRCSYNCPR_PERIOD_S)
+#define TRCCCCTLR 0x038 /* Trace Cycle Count Control Register */
+#define TRCBBCTLR 0x03C /* Trace Branch Broadcast Control Register */
+#define TRCTRACEIDR 0x040 /* Trace Trace ID Register */
+#define TRCQCTLR 0x044 /* Trace Q Element Control Register */
+#define TRCQCTLR_MODE_INC (1 << 8) /* Include mode. */
+#define TRCVICTLR 0x080 /* Trace ViewInst Main Control Register */
+#define TRCVICTLR_SSSTATUS (1 << 9) /* The start/stop logic is in the started state. */
+#define TRCVICTLR_EXLEVEL_NS_S 20
+#define TRCVICTLR_EXLEVEL_NS_M (0xf << TRCVICTLR_EXLEVEL_NS_S)
+#define TRCVICTLR_EXLEVEL_NS(n) (0x1 << ((n) + TRCVICTLR_EXLEVEL_NS_S))
+#define TRCVICTLR_EXLEVEL_S_S 16
+#define TRCVICTLR_EXLEVEL_S_M (0xf << TRCVICTLR_EXLEVEL_S_S)
+#define TRCVICTLR_EXLEVEL_S(n) (0x1 << ((n) + TRCVICTLR_EXLEVEL_S_S))
+#define EVENT_SEL_S 0
+#define EVENT_SEL_M (0x1f << EVENT_SEL_S)
+#define TRCVIIECTLR 0x084 /* Trace ViewInst Include/Exclude Control Register */
+#define TRCVIIECTLR_INCLUDE_S 0
+#define TRCVISSCTLR 0x088 /* Trace ViewInst Start/Stop Control Register */
+#define TRCVIPCSSCTLR 0x08C /* Trace ViewInst Start/Stop PE Comparator Control Register */
+#define TRCVDCTLR 0x0A0 /* Trace ViewData Main Control Register */
+#define TRCVDCTLR_TRCEXDATA (1 << 12) /* Exception and exception return data transfers are traced */
+#define TRCVDCTLR_TBI (1 << 11) /* The trace unit assigns bits[63:56] to have the same value as bits[63:56] of the data address. */
+#define TRCVDCTLR_PCREL (1 << 10) /* The trace unit does not trace the address or value portions of PC-relative transfers. */
+#define TRCVDCTLR_SPREL_S 8
+#define TRCVDCTLR_SPREL_M (0x3 << TRCVDCTLR_SPREL_S)
+#define TRCVDCTLR_EVENT_S 0
+#define TRCVDCTLR_EVENT_M (0xff << TRCVDCTLR_EVENT_S)
+#define TRCVDSACCTLR 0x0A4 /* Trace ViewData Include/Exclude Single Address Comparator Control Register */
+#define TRCVDARCCTLR 0x0A8 /* Trace ViewData Include/Exclude Address Range Comparator Control Register */
+#define TRCSEQEVR(n) (0x100 + (n) * 0x4) /* Trace Sequencer State Transition Control Register [n=0-2] */
+#define TRCSEQRSTEVR 0x118 /* Trace Sequencer Reset Control Register */
+#define TRCSEQSTR 0x11C /* Trace Sequencer State Register */
+#define TRCEXTINSELR 0x120 /* Trace External Input Select Register */
+#define TRCCNTRLDVR(n) (0x140 + (n) * 0x4) /* 32 Trace Counter Reload Value Register [n=0-3] */
+#define TRCCNTCTLR(n) (0x150 + (n) * 0x4) /* 32 Trace Counter Control Register [n=0-3] */
+#define TRCCNTVR(n) (0x160 + (n) * 0x4) /* 32 Trace Counter Value Register [n=0-3] */
+#define TRCIMSPEC(n) (0x1C0 + (n) * 0x4) /* Trace IMPLEMENTATION DEFINED register [n=0-7] */
+
+#define TRCIDR0(n) (0x1E0 + 0x4 * (n))
+#define TRCIDR8(n) (0x180 + 0x4 * (n))
+#define TRCIDR(n) ((n > 7) ? TRCIDR8(n) : TRCIDR0(n))
+#define TRCIDR1_TRCARCHMAJ_S 8
+#define TRCIDR1_TRCARCHMAJ_M (0xf << TRCIDR1_TRCARCHMAJ_S)
+#define TRCIDR1_TRCARCHMIN_S 4
+#define TRCIDR1_TRCARCHMIN_M (0xf << TRCIDR1_TRCARCHMIN_S)
+
+#define TRCRSCTLR(n) (0x200 + (n) * 0x4) /* Trace Resource Selection Control Register [n=2-31] */
+#define TRCSSCCR(n) (0x280 + (n) * 0x4) /* Trace Single-shot Comparator Control Register [n=0-7] */
+#define TRCSSCSR(n) (0x2A0 + (n) * 0x4) /* Trace Single-shot Comparator Status Register [n=0-7] */
+#define TRCSSPCICR(n) (0x2C0 + (n) * 0x4) /* Trace Single-shot PE Comparator Input Control [n=0-7] */
+#define TRCOSLAR 0x300 /* Management OS Lock Access Register */
+#define TRCOSLSR 0x304 /* Management OS Lock Status Register */
+#define TRCPDCR 0x310 /* Management PowerDown Control Register */
+#define TRCPDSR 0x314 /* Management PowerDown Status Register */
+#define TRCACVR(n) (0x400 + (n) * 0x8) /* Trace Address Comparator Value Register [n=0-15] */
+#define TRCACATR(n) (0x480 + (n) * 0x8) /* Trace Address Comparator Access Type Register [n=0-15] */
+#define TRCACATR_DTBM (1 << 21)
+#define TRCACATR_DATARANGE (1 << 20)
+#define TRCACATR_DATASIZE_S 18
+#define TRCACATR_DATASIZE_M (0x3 << TRCACATR_DATASIZE_S)
+#define TRCACATR_DATASIZE_B (0x0 << TRCACATR_DATASIZE_S)
+#define TRCACATR_DATASIZE_HW (0x1 << TRCACATR_DATASIZE_S)
+#define TRCACATR_DATASIZE_W (0x2 << TRCACATR_DATASIZE_S)
+#define TRCACATR_DATASIZE_DW (0x3 << TRCACATR_DATASIZE_S)
+#define TRCACATR_DATAMATCH_S 16
+#define TRCACATR_DATAMATCH_M (0x3 << TRCACATR_DATAMATCH_S)
+#define TRCACATR_EXLEVEL_S_S 8
+#define TRCACATR_EXLEVEL_S_M (0xf << TRCACATR_EXLEVEL_S_S)
+#define TRCACATR_EXLEVEL_S(n) (0x1 << ((n) + TRCACATR_EXLEVEL_S_S))
+#define TRCACATR_EXLEVEL_NS_S 12
+#define TRCACATR_EXLEVEL_NS_M (0xf << TRCACATR_EXLEVEL_NS_S)
+#define TRCACATR_EXLEVEL_NS(n) (0x1 << ((n) + TRCACATR_EXLEVEL_NS_S))
+#define TRCDVCVR(n) (0x500 + (n) * 0x8) /* Trace Data Value Comparator Value Register [n=0-7] */
+#define TRCDVCMR(n) (0x580 + (n) * 0x8) /* Trace Data Value Comparator Mask Register [n=0-7] */
+#define TRCCIDCVR(n) (0x600 + (n) * 0x8) /* Trace Context ID Comparator Value Register [n=0-7] */
+#define TRCVMIDCVR(n) (0x640 + (n) * 0x8) /* Trace Virtual context identifier Comparator Value [n=0-7] */
+#define TRCCIDCCTLR0 0x680 /* Trace Context ID Comparator Control Register 0 */
+#define TRCCIDCCTLR1 0x684 /* Trace Context ID Comparator Control Register 1 */
+#define TRCVMIDCCTLR0 0x688 /* Trace Virtual context identifier Comparator Control Register 0 */
+#define TRCVMIDCCTLR1 0x68C /* Trace Virtual context identifier Comparator Control Register 1 */
+#define TRCITCTRL 0xF00 /* Management Integration Mode Control register */
+#define TRCCLAIMSET 0xFA0 /* Trace Claim Tag Set register */
+#define TRCCLAIMCLR 0xFA4 /* Trace Claim Tag Clear register */
+#define TRCDEVAFF0 0xFA8 /* Management Device Affinity register 0 */
+#define TRCDEVAFF1 0xFAC /* Management Device Affinity register 1 */
+#define TRCLAR 0xFB0 /* Management Software Lock Access Register */
+#define TRCLSR 0xFB4 /* Management Software Lock Status Register */
+#define TRCAUTHSTATUS 0xFB8 /* Management Authentication Status register */
+#define TRCDEVARCH 0xFBC /* Management Device Architecture register */
+#define TRCDEVID 0xFC8 /* Management Device ID register */
+#define TRCDEVTYPE 0xFCC /* Management Device Type register */
+#define TRCPIDR4 0xFD0 /* Management Peripheral ID4 Register */
+#define TRCPIDR(n) (0xFE0 + (n) * 0x4) /* Management Peripheral IDn Register [n=0-3] */
+#define TRCPIDR567(n) (0xFD4 + ((n) - 5) * 0x4) /* Management Peripheral ID5 to Peripheral ID7 Registers */
+#define TRCCIDR(n) (0xFF0 + (n) * 0x4) /* Management Component IDn Register [n=0-4] */
+
+/* ETMv4 resources */
+#define ETM_MAX_NR_PE 8
+#define ETMv4_MAX_CNTR 4
+#define ETM_MAX_SEQ_STATES 4
+#define ETM_MAX_EXT_INP_SEL 4
+#define ETM_MAX_EXT_INP 256
+#define ETM_MAX_EXT_OUT 4
+#define ETM_MAX_SINGLE_ADDR_CMP 16
+#define ETM_MAX_ADDR_RANGE_CMP (ETM_MAX_SINGLE_ADDR_CMP / 2)
+#define ETM_MAX_DATA_VAL_CMP 8
+#define ETMv4_MAX_CTXID_CMP 8
+#define ETM_MAX_VMID_CMP 8
+#define ETM_MAX_PE_CMP 8
+#define ETM_MAX_RES_SEL 32
+#define ETM_MAX_SS_CMP 8
+
+/**
+ * struct etmv4_config - configuration information related to an ETMv4
+ * @mode: Controls various modes supported by this ETM.
+ * @pe_sel: Controls which PE to trace.
+ * @cfg: Controls the tracing options.
+ * @eventctrl0: Controls the tracing of arbitrary events.
+ * @eventctrl1: Controls the behavior of the events that @event_ctrl0 selects.
+ * @stallctl: If functionality that prevents trace unit buffer overflows
+ * is available.
+ * @ts_ctrl: Controls the insertion of global timestamps in the
+ * trace streams.
+ * @syncfreq: Controls how often trace synchronization requests occur.
+ * the TRCCCCTLR register.
+ * @ccctlr: Sets the threshold value for cycle counting.
+ * @vinst_ctrl: Controls instruction trace filtering.
+ * @viiectlr: Set or read, the address range comparators.
+ * @vissctlr: Set, or read, the single address comparators that control the
+ * ViewInst start-stop logic.
+ * @vipcssctlr: Set, or read, which PE comparator inputs can control the
+ * ViewInst start-stop logic.
+ * @seq_idx: Sequencor index selector.
+ * @seq_ctrl: Control for the sequencer state transition control register.
+ * @seq_rst: Moves the sequencer to state 0 when a programmed event occurs.
+ * @seq_state: Set, or read the sequencer state.
+ * @cntr_idx: Counter index seletor.
+ * @cntrldvr: Sets or returns the reload count value for a counter.
+ * @cntr_ctrl: Controls the operation of a counter.
+ * @cntr_val: Sets or returns the value for a counter.
+ * @res_idx: Resource index selector.
+ * @res_ctrl: Controls the selection of the resources in the trace unit.
+ * @ss_idx: Single-shot index selector.
+ * @ss_ctrl: Controls the corresponding single-shot comparator resource.
+ * @ss_status: The status of the corresponding single-shot comparator.
+ * @ss_pe_cmp: Selects the PE comparator inputs for Single-shot control.
+ * @addr_idx: Address comparator index selector.
+ * @addr_val: Value for address comparator.
+ * @addr_acc: Address comparator access type.
+ * @addr_type: Current status of the comparator register.
+ * @ctxid_idx: Context ID index selector.
+ * @ctxid_pid: Value of the context ID comparator.
+ * @ctxid_mask0:Context ID comparator mask for comparator 0-3.
+ * @ctxid_mask1:Context ID comparator mask for comparator 4-7.
+ * @vmid_idx: VM ID index selector.
+ * @vmid_val: Value of the VM ID comparator.
+ * @vmid_mask0: VM ID comparator mask for comparator 0-3.
+ * @vmid_mask1: VM ID comparator mask for comparator 4-7.
+ * @ext_inp: External input selection.
+ * @s_ex_level: Secure ELs where tracing is supported.
+ */
+
+struct etmv4_config {
+ uint32_t mode;
+ uint32_t pe_sel;
+ uint32_t cfg;
+ uint32_t eventctrl0;
+ uint32_t eventctrl1;
+ uint32_t stall_ctrl;
+ uint32_t ts_ctrl;
+ uint32_t syncfreq;
+ uint32_t ccctlr;
+ uint32_t bb_ctrl;
+ uint32_t vinst_ctrl;
+ uint32_t viiectlr;
+ uint32_t vissctlr;
+ uint32_t vipcssctlr;
+ uint8_t seq_idx;
+ uint32_t seq_ctrl[ETM_MAX_SEQ_STATES];
+ uint32_t seq_rst;
+ uint32_t seq_state;
+ uint8_t cntr_idx;
+ uint32_t cntrldvr[ETMv4_MAX_CNTR];
+ uint32_t cntr_ctrl[ETMv4_MAX_CNTR];
+ uint32_t cntr_val[ETMv4_MAX_CNTR];
+ uint8_t res_idx;
+ uint32_t res_ctrl[ETM_MAX_RES_SEL];
+ uint8_t ss_idx;
+ uint32_t ss_ctrl[ETM_MAX_SS_CMP];
+ uint32_t ss_status[ETM_MAX_SS_CMP];
+ uint32_t ss_pe_cmp[ETM_MAX_SS_CMP];
+ uint8_t addr_idx;
+ uint64_t addr_val[ETM_MAX_SINGLE_ADDR_CMP];
+ uint64_t addr_acc[ETM_MAX_SINGLE_ADDR_CMP];
+ uint8_t addr_type[ETM_MAX_SINGLE_ADDR_CMP];
+ uint8_t ctxid_idx;
+ uint64_t ctxid_pid[ETMv4_MAX_CTXID_CMP];
+ uint32_t ctxid_mask0;
+ uint32_t ctxid_mask1;
+ uint8_t vmid_idx;
+ uint64_t vmid_val[ETM_MAX_VMID_CMP];
+ uint32_t vmid_mask0;
+ uint32_t vmid_mask1;
+ uint32_t ext_inp;
+ uint8_t s_ex_level;
+};
+
+extern struct trace_dev_methods cs_methods;
+
+#endif /* !_HWT_CORESIGHT_H_ */
Index: usr.sbin/hwt/hwt_coresight.c
===================================================================
--- /dev/null
+++ usr.sbin/hwt/hwt_coresight.c
@@ -0,0 +1,693 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * 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.
+ */
+
+/* ARM CoreSight tracing unit. */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/errno.h>
+#include <sys/cpuset.h>
+#include <sys/hwt.h>
+#include <sys/wait.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <opencsd/c_api/ocsd_c_api_types.h>
+#include <opencsd/c_api/opencsd_c_api.h>
+
+#include "hwtvar.h"
+#include "hwt_coresight.h"
+
+#include "libpmcstat_stubs.h"
+#include <libpmcstat.h>
+
+#define PMCTRACE_CS_DEBUG
+#undef PMCTRACE_CS_DEBUG
+
+#ifdef PMCTRACE_CS_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+static int cs_flags = 0;
+#define FLAG_FORMAT (1 << 0)
+#define FLAG_FRAME_RAW_UNPACKED (1 << 1)
+#define FLAG_FRAME_RAW_PACKED (1 << 2)
+#define FLAG_CALLBACK_MEM_ACC (1 << 3)
+
+#define PACKET_STR_LEN 1024
+static char packet_str[PACKET_STR_LEN];
+
+struct cs_decoder {
+ dcd_tree_handle_t dcdtree_handle;
+ int dp_ret;
+};
+
+static ocsd_err_t
+attach_raw_printers(dcd_tree_handle_t dcd_tree_h)
+{
+ ocsd_err_t err;
+ int flags;
+
+ flags = 0;
+ err = OCSD_OK;
+
+ if (cs_flags & FLAG_FRAME_RAW_UNPACKED)
+ flags |= OCSD_DFRMTR_UNPACKED_RAW_OUT;
+
+ if (cs_flags & FLAG_FRAME_RAW_PACKED)
+ flags |= OCSD_DFRMTR_PACKED_RAW_OUT;
+
+ if (flags)
+ err = ocsd_dt_set_raw_frame_printer(dcd_tree_h, flags);
+
+ return err;
+}
+
+static int
+print_data_array(const uint8_t *p_array, const int array_size,
+ char *p_buffer, int buf_size)
+{
+ int bytes_processed;
+ int chars_printed;
+
+ chars_printed = 0;
+ p_buffer[0] = 0;
+
+ if (buf_size > 9) {
+ strcat(p_buffer, "[ ");
+ chars_printed += 2;
+
+ for (bytes_processed = 0; bytes_processed < array_size;
+ bytes_processed++) {
+ sprintf(p_buffer + chars_printed, "0x%02X ",
+ p_array[bytes_processed]);
+ chars_printed += 5;
+ if ((chars_printed + 5) > buf_size)
+ break;
+ }
+
+ strcat(p_buffer, "];");
+ chars_printed += 2;
+ } else if (buf_size >= 4) {
+ sprintf(p_buffer, "[];");
+ chars_printed += 3;
+ }
+
+ return (chars_printed);
+}
+
+static void
+packet_monitor(void *context __unused,
+ const ocsd_datapath_op_t op,
+ const ocsd_trc_index_t index_sop,
+ const void *p_packet_in,
+ const uint32_t size,
+ const uint8_t *p_data)
+{
+ int offset;
+
+ offset = 0;
+
+ switch (op) {
+ case OCSD_OP_DATA:
+ sprintf(packet_str, "Idx:%" OCSD_TRC_IDX_STR ";", index_sop);
+ offset = strlen(packet_str);
+ offset += print_data_array(p_data, size, packet_str + offset,
+ PACKET_STR_LEN - offset);
+
+ /*
+ * Got a packet -- convert to string and use the libraries'
+ * message output to print to file and stdoout
+ */
+
+ if (ocsd_pkt_str(OCSD_PROTOCOL_ETMV4I, p_packet_in,
+ packet_str + offset, PACKET_STR_LEN - offset) == OCSD_OK) {
+ /* add in <CR> */
+ if (strlen(packet_str) == PACKET_STR_LEN - 1)/*maxlen*/
+ packet_str[PACKET_STR_LEN - 2] = '\n';
+ else
+ strcat(packet_str,"\n");
+
+ /* print it using the library output logger. */
+ ocsd_def_errlog_msgout(packet_str);
+ }
+ break;
+
+ case OCSD_OP_EOT:
+ sprintf(packet_str,"**** END OF TRACE ****\n");
+ ocsd_def_errlog_msgout(packet_str);
+ break;
+ default:
+ printf("%s: unknown op %d\n", __func__, op);
+ break;
+ }
+}
+
+#if 0
+static uint32_t
+cs_decoder__mem_access(const void *context __unused,
+ const ocsd_vaddr_t address __unused,
+ const ocsd_mem_space_acc_t mem_space __unused,
+ const uint32_t req_size __unused, uint8_t *buffer __unused)
+{
+
+ /* TODO */
+
+ return (0);
+}
+#endif
+
+static ocsd_err_t
+create_test_memory_acc(dcd_tree_handle_t handle, struct trace_context *tc)
+{
+ ocsd_vaddr_t address;
+ uint8_t *p_mem_buffer;
+ uint32_t mem_length;
+ int ret;
+
+ dprintf("%s\n", __func__);
+
+#if 0
+ if (cs_flags & FLAG_CALLBACK_MEM_ACC)
+ ret = ocsd_dt_add_callback_mem_acc(handle, base + start,
+ base + end - 1, OCSD_MEM_SPACE_ANY,
+ cs_decoder__mem_access, NULL);
+ else
+#endif
+ {
+ address = (ocsd_vaddr_t)tc->base;
+
+ uint64_t *t;
+ t = (uint64_t *)tc->base;
+ printf("%lx %lx %lx %lx\n", t[0], t[1], t[2], t[3]);
+
+ p_mem_buffer = (uint8_t *)tc->base;
+ mem_length = tc->bufsize;
+
+ ret = ocsd_dt_add_buffer_mem_acc(handle, address,
+ OCSD_MEM_SPACE_ANY, p_mem_buffer, mem_length);
+ }
+
+ if (ret != OCSD_OK)
+ printf("%s: can't create memory accessor: ret %d\n",
+ __func__, ret);
+
+ return (ret);
+}
+
+static ocsd_err_t
+create_generic_decoder(dcd_tree_handle_t handle, const char *p_name,
+ const void *p_cfg, const void *p_context __unused,
+ struct trace_context *tc)
+{
+ ocsd_err_t ret;
+ uint8_t CSID;
+
+ CSID = 0;
+
+ dprintf("%s\n", __func__);
+
+ ret = ocsd_dt_create_decoder(handle, p_name,
+ OCSD_CREATE_FLG_FULL_DECODER, p_cfg, &CSID);
+ if (ret != OCSD_OK)
+ return (-1);
+
+ printf("%s: CSID %d\n", __func__, CSID);
+
+ if (cs_flags & FLAG_FORMAT) {
+ ret = ocsd_dt_attach_packet_callback(handle, CSID,
+ OCSD_C_API_CB_PKT_MON, packet_monitor, p_context);
+ if (ret != OCSD_OK)
+ return (-1);
+ }
+
+ /* attach a memory accessor */
+ ret = create_test_memory_acc(handle, tc);
+ if (ret != OCSD_OK)
+ ocsd_dt_remove_decoder(handle, CSID);
+
+ return (ret);
+}
+
+static ocsd_err_t
+create_decoder_etmv4(struct trace_context *tc, dcd_tree_handle_t dcd_tree_h)
+{
+ ocsd_etmv4_cfg trace_config;
+ ocsd_err_t ret;
+
+ trace_config.arch_ver = ARCH_V8;
+ trace_config.core_prof = profile_CortexA;
+
+ trace_config.reg_configr = 0x00001fc6;
+ trace_config.reg_configr = 0x000000C1;
+ trace_config.reg_traceidr = tc->thread_id + 1;
+
+ trace_config.reg_idr0 = 0x28000ea1;
+ trace_config.reg_idr1 = 0x4100f424;
+ trace_config.reg_idr2 = 0x20001088;
+ trace_config.reg_idr8 = 0x0;
+ trace_config.reg_idr9 = 0x0;
+ trace_config.reg_idr10 = 0x0;
+ trace_config.reg_idr11 = 0x0;
+ trace_config.reg_idr12 = 0x0;
+ trace_config.reg_idr13 = 0x0;
+
+ /* Instruction decoder. */
+ ret = create_generic_decoder(dcd_tree_h, OCSD_BUILTIN_DCD_ETMV4I,
+ (void *)&trace_config, 0, tc);
+
+ return (ret);
+}
+
+static int
+cs_process_chunk_raw(struct trace_context *tc, size_t start, size_t len,
+ uint32_t *consumed)
+{
+ void *base;
+
+ base = (void *)((uintptr_t)tc->base + (uintptr_t)start);
+
+ fwrite(base, len, 1, tc->f);
+
+ *consumed = len;
+
+ return (0);
+}
+
+static int
+cs_process_chunk(struct trace_context *tc, struct cs_decoder *dec,
+ size_t start, size_t len, uint32_t *consumed)
+{
+ void *base;
+ int error;
+
+ if (tc->raw) {
+ error = cs_process_chunk_raw(tc, start, len, consumed);
+ return (error);
+ }
+
+ base = (void *)((uintptr_t)tc->base + (uintptr_t)start);
+
+ error = ocsd_dt_process_data(dec->dcdtree_handle,
+ OCSD_OP_DATA, start, len, base, consumed);
+
+ if (*consumed != len) {
+ printf("error");
+ exit(5);
+ }
+
+ return (error);
+}
+
+struct pmcstat_pcmap *
+pmcstat_process_find_map(struct pmcstat_process *p, uintfptr_t pc)
+{
+ struct pmcstat_pcmap *ppm;
+
+ TAILQ_FOREACH(ppm, &p->pp_map, ppm_next) {
+ if (pc >= ppm->ppm_lowpc && pc < ppm->ppm_highpc)
+ return (ppm);
+ if (pc < ppm->ppm_lowpc)
+ return (NULL);
+ }
+
+ return (NULL);
+}
+
+static struct pmcstat_symbol *
+symbol_lookup(const struct trace_context *tc, uint64_t ip,
+ struct pmcstat_image **img, uint64_t *newpc0)
+{
+ struct pmcstat_image *image;
+ struct pmcstat_symbol *sym;
+ struct pmcstat_pcmap *map;
+ uint64_t newpc;
+
+ map = pmcstat_process_find_map(tc->pp, ip);
+ if (map != NULL) {
+ image = map->ppm_image;
+ newpc = ip - ((unsigned long)map->ppm_lowpc +
+ (image->pi_vaddr - image->pi_start));
+ sym = pmcstat_symbol_search(image, newpc); /* Could be NULL. */
+ newpc += image->pi_vaddr;
+
+ *img = image;
+ *newpc0 = newpc;
+
+ return (sym);
+ } else
+ *img = NULL;
+
+ return (NULL);
+}
+
+
+static ocsd_datapath_resp_t
+gen_trace_elem_print_lookup(const void *p_context,
+ const ocsd_trc_index_t index_sop __unused,
+ const uint8_t trc_chan_id __unused,
+ const ocsd_generic_trace_elem *elem)
+{
+ const struct trace_context *tc;
+ struct pmcstat_image *image;
+ ocsd_datapath_resp_t resp;
+ struct pmcstat_symbol *sym;
+ unsigned long offset;
+ uint64_t newpc;
+ uint64_t ip;
+ FILE *out;
+
+ tc = (const struct trace_context *)p_context;
+ if (tc->filename)
+ out = tc->f;
+ else
+ out = stdout;
+
+ resp = OCSD_RESP_CONT;
+
+#if 0
+ dprintf("%s: Idx:%d ELEM TYPE %d, st_addr %lx, en_addr %lx\n",
+ __func__, index_sop, elem->elem_type,
+ elem->st_addr, elem->en_addr);
+#endif
+
+#if 0
+ if (elem->st_addr == -1)
+ return (resp);
+#endif
+
+ if (elem->st_addr == 0)
+ return (resp);
+ ip = elem->st_addr;
+
+ sym = symbol_lookup(tc, ip, &image, &newpc);
+
+ static const char *ARMv8Excep[] = {
+ "PE Reset", "Debug Halt", "Call", "Trap",
+ "System Error", "Reserved", "Inst Debug", "Data Debug",
+ "Reserved", "Reserved", "Alignment", "Inst Fault",
+ "Data Fault", "Reserved", "IRQ", "FIQ"
+ };
+
+ switch (elem->elem_type) {
+ case OCSD_GEN_TRC_ELEM_UNKNOWN:
+ fprintf(out, "Unknown packet.\n");
+ return (resp);
+ case OCSD_GEN_TRC_ELEM_NO_SYNC:
+ fprintf(out, "No sync.\n");
+ return (resp);
+ case OCSD_GEN_TRC_ELEM_TRACE_ON:
+ fprintf(out, "Trace on.\n");
+ return (resp);
+ case OCSD_GEN_TRC_ELEM_EO_TRACE:
+ fprintf(out, "End of Trace.\n");
+ return (resp);
+ case OCSD_GEN_TRC_ELEM_PE_CONTEXT:
+ break;
+ case OCSD_GEN_TRC_ELEM_INSTR_RANGE:
+ case OCSD_GEN_TRC_ELEM_I_RANGE_NOPATH:
+ return (resp);
+ case OCSD_GEN_TRC_ELEM_ADDR_NACC:
+ break;
+ case OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN:
+ return (resp);
+ case OCSD_GEN_TRC_ELEM_EXCEPTION:
+ fprintf(out, "Exception #%d (%s)\n", elem->exception_number,
+ ARMv8Excep[elem->exception_number]);
+ return (resp);
+ case OCSD_GEN_TRC_ELEM_EXCEPTION_RET:
+ fprintf(out, "Exception RET to %lx\n", elem->st_addr);
+ return (resp);
+ case OCSD_GEN_TRC_ELEM_TIMESTAMP:
+ fprintf(out, "Timestamp: %lx\n", elem->timestamp);
+ return (resp);
+ case OCSD_GEN_TRC_ELEM_CYCLE_COUNT:
+ fprintf(out, "Cycle count: %d\n", elem->cycle_count);
+ return (resp);
+ case OCSD_GEN_TRC_ELEM_EVENT:
+ case OCSD_GEN_TRC_ELEM_SWTRACE:
+ case OCSD_GEN_TRC_ELEM_SYNC_MARKER:
+ case OCSD_GEN_TRC_ELEM_MEMTRANS:
+ case OCSD_GEN_TRC_ELEM_INSTRUMENTATION:
+ case OCSD_GEN_TRC_ELEM_CUSTOM:
+ return (resp);
+ };
+
+#if 0
+ char ts[100];
+
+ if (elem->timestamp != 0)
+ sprintf(ts, "ts %ld", elem->timestamp);
+ else
+ sprintf(ts, " ");
+#endif
+
+ if (sym) {
+ offset = newpc - (sym->ps_start + image->pi_vaddr);
+
+ fprintf(out, "pc 0x%08lx (%lx)\t%12s\t%s+0x%lx\n",
+ //elem->elem_type,
+ ip, newpc,
+ pmcstat_string_unintern(image->pi_name),
+ pmcstat_string_unintern(sym->ps_name), offset);
+ } else
+ if (image)
+ fprintf(out, "pc 0x%08lx (%lx)\t%12s\n",
+ //elem->elem_type,
+ ip, newpc,
+ pmcstat_string_unintern(image->pi_name));
+ else {
+ /* image not found. */
+ }
+
+ return (resp);
+}
+
+static int
+hwt_coresight_init(struct trace_context *tc, struct cs_decoder *dec)
+{
+ int error;
+
+ ocsd_def_errlog_init(OCSD_ERR_SEV_INFO, 1);
+
+ dec->dp_ret = OCSD_RESP_CONT;
+ dec->dcdtree_handle = ocsd_create_dcd_tree(OCSD_TRC_SRC_FRAME_FORMATTED,
+ OCSD_DFRMTR_FRAME_MEM_ALIGN);
+ if (dec->dcdtree_handle == C_API_INVALID_TREE_HANDLE) {
+ printf("can't find dcd tree\n");
+ return (-1);
+ }
+
+ //cs_flags |= FLAG_FORMAT;
+ //cs_flags |= FLAG_FRAME_RAW_UNPACKED;
+ //cs_flags |= FLAG_FRAME_RAW_PACKED;
+
+ error = create_decoder_etmv4(tc, dec->dcdtree_handle);
+ if (error != OCSD_OK) {
+ printf("can't create decoder: tc->base %#p\n", tc->base);
+ return (-2);
+ }
+
+#ifdef PMCTRACE_CS_DEBUG
+ ocsd_tl_log_mapped_mem_ranges(dec->dcdtree_handle);
+#endif
+
+ if (cs_flags & FLAG_FORMAT)
+ ocsd_dt_set_gen_elem_printer(dec->dcdtree_handle);
+ else
+ ocsd_dt_set_gen_elem_outfn(dec->dcdtree_handle,
+ gen_trace_elem_print_lookup, tc);
+
+ attach_raw_printers(dec->dcdtree_handle);
+
+ return (0);
+}
+
+static void
+hwt_coresight_fill_config(struct trace_context *tc, struct etmv4_config *config)
+{
+ int excp_level;
+ uint32_t reg;
+ uint32_t val;
+ int i;
+
+ memset(config, 0, sizeof(struct etmv4_config));
+
+ reg = TRCCONFIGR_RS | TRCCONFIGR_TS;
+ reg |= TRCCONFIGR_CID | TRCCONFIGR_VMID;
+ reg |= TRCCONFIGR_INSTP0_LDRSTR;
+ reg |= TRCCONFIGR_COND_ALL;
+ config->cfg = reg;
+
+ config->ts_ctrl = 0;
+ config->syncfreq = TRCSYNCPR_4K;
+
+ if (tc->mode == HWT_MODE_THREAD)
+ excp_level = 0; /* User mode. */
+ else
+ excp_level = 1; /* CPU mode. */
+
+ reg = TRCVICTLR_SSSTATUS;
+ reg |= (1 << EVENT_SEL_S);
+ reg |= TRCVICTLR_EXLEVEL_NS(1 << excp_level);
+ reg |= TRCVICTLR_EXLEVEL_S(1 << excp_level);
+ config->vinst_ctrl = reg;
+
+ /* Address-range filtering. */
+ val = 0;
+ for (i = 0; i < tc->nranges * 2; i++) {
+ config->addr_val[i] = tc->addr_ranges[i];
+
+ reg = TRCACATR_EXLEVEL_S(1 << excp_level);
+ reg |= TRCACATR_EXLEVEL_NS(1 << excp_level);
+ config->addr_acc[i] = reg;
+
+ /* Include the range ID. */
+ val |= (1 << (TRCVIIECTLR_INCLUDE_S + i / 2));
+ }
+ config->viiectlr = val;
+}
+
+static int
+hwt_coresight_set_config(struct trace_context *tc)
+{
+ struct hwt_set_config sconf;
+ struct etmv4_config *config;
+ int error;
+
+ config = malloc(sizeof(struct etmv4_config));
+ hwt_coresight_fill_config(tc, config);
+
+ tc->config = config;
+
+ sconf.config = config;
+ sconf.config_size = sizeof(struct etmv4_config);
+ sconf.config_version = 1;
+ sconf.pause_on_mmap = tc->suspend_on_mmap ? 1 : 0;
+
+ error = ioctl(tc->thr_fd, HWT_IOC_SET_CONFIG, &sconf);
+
+ return (error);
+}
+
+static int
+hwt_coresight_process(struct trace_context *tc)
+{
+ size_t offs;
+ size_t new_offs;
+ int error;
+ int t;
+ struct cs_decoder *dec;
+ uint32_t processed;
+ size_t cursor;
+ int len;
+ size_t totals;
+
+ /* Coresight data is always on CPU0 due to funnelling by HW. */
+
+ dec = malloc(sizeof(struct cs_decoder));
+
+ hwt_coresight_init(tc, dec);
+
+ error = hwt_get_offs(tc, &offs);
+ if (error) {
+ printf("%s: cant get offset\n", __func__);
+ return (-1);
+ }
+
+#if 0
+ printf("data to process %ld\n", offs);
+#endif
+
+ cursor = 0;
+ processed = 0;
+ totals = 0;
+ len = offs;
+
+ cs_process_chunk(tc, dec, cursor, len, &processed);
+ cursor += processed;
+ totals += processed;
+
+ t = 0;
+
+ while (1) {
+ error = hwt_get_offs(tc, &new_offs);
+ if (error)
+ return (-1);
+
+ if (new_offs == cursor) {
+ /* No new entries in trace. */
+ if (tc->terminate && t++ > 2)
+ break;
+ hwt_sleep();
+ } else if (new_offs > cursor) {
+ /* New entries in the trace buffer. */
+ len = new_offs - cursor;
+ cs_process_chunk(tc, dec, cursor, len, &processed);
+ cursor += processed;
+ totals += processed;
+ t = 0;
+
+ } else if (new_offs < cursor) {
+ /* New entries in the trace buffer. Buffer wrapped. */
+ len = tc->bufsize - cursor;
+ cs_process_chunk(tc, dec, cursor, len, &processed);
+ cursor += processed;
+ totals += processed;
+
+ cursor = 0;
+ len = new_offs;
+ cs_process_chunk(tc, dec, cursor, len, &processed);
+ cursor += processed;
+ totals += processed;
+ t = 0;
+ }
+ }
+
+ printf("\nBytes processed: %ld\n", totals);
+
+ return (0);
+}
+
+struct trace_dev_methods cs_methods = {
+ .process = hwt_coresight_process,
+ .set_config = hwt_coresight_set_config,
+};
Index: usr.sbin/hwt/hwt_elf.c
===================================================================
--- /dev/null
+++ usr.sbin/hwt/hwt_elf.c
@@ -0,0 +1,136 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * 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 <sys/param.h>
+#include <sys/types.h>
+#include <sys/cpuset.h>
+#include <sys/hwt.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <gelf.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hwtvar.h"
+
+int
+hwt_elf_count_libs(const char *elf_path, uint32_t *nlibs0)
+{
+ GElf_Shdr shdr;
+ GElf_Phdr ph;
+ GElf_Ehdr eh;
+ Elf_Scn *scn;
+ Elf *elf;
+ size_t sh_entsize;
+ Elf_Data *data;
+ GElf_Dyn dyn;
+ int is_dynamic;
+ uint32_t nlibs;
+ int fd;
+ size_t i;
+
+ nlibs = 0;
+
+ assert(elf_version(EV_CURRENT) != EV_NONE);
+
+ fd = open(elf_path, O_RDONLY, 0);
+
+ assert(fd >= 0);
+
+ elf = elf_begin(fd, ELF_C_READ, NULL);
+
+ assert(elf != NULL);
+ assert(elf_kind(elf) == ELF_K_ELF);
+
+ if (gelf_getehdr(elf, &eh) != &eh) {
+ printf("could not find elf header\n");
+ return (-1);
+ }
+
+ if (eh.e_type != ET_EXEC && eh.e_type != ET_DYN) {
+ printf("unsupported image\n");
+ return (-2);
+ }
+
+ if (eh.e_ident[EI_CLASS] != ELFCLASS32 &&
+ eh.e_ident[EI_CLASS] != ELFCLASS64)
+ return (-3);
+
+ is_dynamic = 0;
+
+ for (i = 0; i < eh.e_phnum; i++) {
+ if (gelf_getphdr(elf, i, &ph) != &ph) {
+ printf("could not get program header %zu\n", i);
+ return (-4);
+ }
+ switch (ph.p_type) {
+ case PT_DYNAMIC:
+ is_dynamic = 1;
+ break;
+ case PT_INTERP:
+ nlibs++;
+ break;
+ }
+ }
+
+ if (!is_dynamic)
+ goto done;
+
+ scn = NULL;
+ data = NULL;
+
+ while ((scn = elf_nextscn(elf, scn)) != NULL) {
+ assert(gelf_getshdr(scn, &shdr) == &shdr);
+
+ if (shdr.sh_type == SHT_DYNAMIC) {
+ data = elf_getdata(scn, data);
+ assert(data != NULL);
+
+ sh_entsize = gelf_fsize(elf, ELF_T_DYN, 1, EV_CURRENT);
+
+ for (i = 0; i < shdr.sh_size / sh_entsize; i++) {
+ assert(gelf_getdyn(data, i, &dyn) == &dyn);
+ if (dyn.d_tag == DT_NEEDED)
+ nlibs++;
+ }
+ }
+ }
+
+done:
+ assert(elf_end(elf) == 0);
+ assert(close(fd) == 0);
+
+ *nlibs0 = nlibs;
+
+ return (0);
+}
Index: usr.sbin/hwt/hwt_process.c
===================================================================
--- /dev/null
+++ usr.sbin/hwt/hwt_process.c
@@ -0,0 +1,141 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * 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 <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/errno.h>
+#include <sys/wait.h>
+#include <sys/cpuset.h>
+#include <sys/hwt.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sysexits.h>
+#include <string.h>
+
+#include "hwtvar.h"
+
+#include "libpmcstat_stubs.h"
+#include <libpmcstat.h>
+
+struct pmcstat_image_hash_list pmcstat_image_hash[PMCSTAT_NHASH];
+
+int
+hwt_process_start(int *sockpair)
+{
+ int error;
+
+ error = write(sockpair[PARENTSOCKET], "!", 1);
+ if (error != 1)
+ return (-1);
+
+ return (0);
+}
+
+static void
+hwt_process_onsig(int signo)
+{
+ pid_t pid;
+ int status;
+
+ assert(signo == SIGCHLD);
+
+ while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
+ if (WIFEXITED(status))
+ hwt_procexit(pid, WEXITSTATUS(status));
+}
+
+int
+hwt_process_create(int *sockpair, char **cmd, char **env __unused, int *pid0)
+{
+ char token;
+ pid_t pid;
+ int error;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair) < 0)
+ return (-1);
+
+ signal(SIGCHLD, hwt_process_onsig);
+
+ pid = fork();
+
+ switch (pid) {
+ case -1:
+ return (-1);
+ case 0:
+ /* Child */
+ close(sockpair[PARENTSOCKET]);
+
+ error = write(sockpair[CHILDSOCKET], "+", 1);
+ if (error != 1)
+ return (-1);
+
+ error = read(sockpair[CHILDSOCKET], &token, 1);
+ if (error < 0)
+ return (-2);
+
+ if (token != '!')
+ return (-3);
+
+ close(sockpair[CHILDSOCKET]);
+
+ execvp(cmd[0], cmd);
+
+ kill(getppid(), SIGCHLD);
+
+ exit(-3);
+ default:
+ /* Parent */
+ close(sockpair[CHILDSOCKET]);
+ break;
+ }
+
+ *pid0 = pid;
+
+ return (0);
+}
+
+struct pmcstat_process *
+hwt_process_alloc(void)
+{
+ struct pmcstat_process *pp;
+
+ pp = malloc(sizeof(struct pmcstat_process));
+ if (pp)
+ TAILQ_INIT(&pp->pp_map);
+
+ return (pp);
+}
Index: usr.sbin/hwt/hwt_record.c
===================================================================
--- /dev/null
+++ usr.sbin/hwt/hwt_record.c
@@ -0,0 +1,137 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * 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 <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/errno.h>
+#include <sys/cpuset.h>
+#include <sys/hwt.h>
+#include <sys/hwt_record.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+
+#include "hwtvar.h"
+
+#include "libpmcstat_stubs.h"
+#include <libpmcstat.h>
+
+int
+hwt_record_fetch(struct trace_context *tc, int *nrecords)
+{
+ struct hwt_record_user_entry *entry;
+ pmcstat_interned_string path;
+ struct pmcstat_image *image;
+ struct pmc_plugins plugins;
+ struct pmcstat_args args;
+ unsigned long addr;
+ struct hwt_record_get record_get;
+ int nentries;
+ int error;
+ int j;
+
+ memset(&plugins, 0, sizeof(struct pmc_plugins));
+ memset(&args, 0, sizeof(struct pmcstat_args));
+ args.pa_fsroot = "/";
+ nentries = 256;
+
+ tc->records = malloc(sizeof(struct hwt_record_user_entry) * nentries);
+
+ record_get.records = tc->records;
+ record_get.nentries = &nentries;
+
+ error = ioctl(tc->thr_fd, HWT_IOC_RECORD_GET, &record_get);
+ if (error != 0) {
+ printf("RECORD_GET error %d entires %d\n",
+ error, nentries);
+ return (error);
+ }
+
+printf("%s: error %d: nent %d\n", __func__, error, nentries);
+
+ for (j = 0; j < nentries; j++) {
+ entry = &tc->records[j];
+
+ switch (entry->record_type) {
+ case HWT_RECORD_MMAP:
+ case HWT_RECORD_MUNMAP:
+ case HWT_RECORD_EXECUTABLE:
+ case HWT_RECORD_INTERP:
+ printf(" lib #%d: path %s addr %lx\n", j,
+ entry->fullpath,
+ (unsigned long)entry->addr);
+
+ path = pmcstat_string_intern(entry->fullpath);
+ if ((image = pmcstat_image_from_path(path, 0,
+ &args, &plugins)) == NULL)
+ return (-1);
+
+ if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
+ pmcstat_image_determine_type(image, &args);
+
+ addr = (unsigned long)entry->addr & ~1;
+ addr -= (image->pi_start - image->pi_vaddr);
+ pmcstat_image_link(tc->pp, image, addr);
+#if 0
+ printf("image pi_vaddr %lx pi_start %lx pi_entry %lx\n",
+ (unsigned long)image->pi_vaddr,
+ (unsigned long)image->pi_start,
+ (unsigned long)image->pi_entry);
+#endif
+ hwt_mmap_received(tc, entry);
+ break;
+ case HWT_RECORD_KERNEL:
+ path = pmcstat_string_intern(entry->fullpath);
+ if ((image = pmcstat_image_from_path(path, 1,
+ &args, &plugins)) == NULL)
+ return (-1);
+ if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN)
+ pmcstat_image_determine_type(image, &args);
+ addr = (unsigned long)entry->addr & ~1;
+ pmcstat_image_link(tc->pp, image, addr);
+ break;
+ case HWT_RECORD_THREAD_CREATE:
+ case HWT_RECORD_THREAD_SET_NAME:
+ break;
+ default:
+ break;
+ }
+ }
+
+ *nrecords = nentries;
+
+ return (0);
+}
Index: usr.sbin/hwt/hwtvar.h
===================================================================
--- /dev/null
+++ usr.sbin/hwt/hwtvar.h
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * 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.
+ */
+
+#ifndef _HWTVAR_H_
+#define _HWTVAR_H_
+
+#define TC_MAX_ADDR_RANGES 16
+
+struct trace_context;
+
+struct trace_dev_methods {
+ int (*process)(struct trace_context *tc);
+ int (*set_config)(struct trace_context *tc);
+};
+
+struct trace_dev {
+ const char *name;
+ const char *fullname;
+ struct trace_dev_methods *methods;
+};
+
+struct trace_context {
+ struct trace_dev *trace_dev;
+ struct pmcstat_process *pp;
+ struct hwt_record_user_entry *records;
+ void *base;
+ size_t bufsize;
+ int pid;
+ int cpu;
+ int fd;
+ int thr_fd;
+ int terminate;
+
+ int thread_id;
+ int ident;
+
+ /* Address range filtering. */
+ int suspend_on_mmap;
+ char *image_name;
+ char *func_name;
+ uintptr_t addr_ranges[TC_MAX_ADDR_RANGES * 2];
+ int nranges;
+
+ /* Backend-specific config. */
+ void *config;
+
+ /* Raw trace. */
+ int raw;
+
+ /* Trace file. */
+ char *filename;
+ FILE *f;
+
+ int mode;
+};
+
+struct pmcstat_process *hwt_process_alloc(void);
+int hwt_process_create(int *sockpair, char **cmd, char **env, int *pid0);
+int hwt_process_start(int *sockpair);
+int hwt_record_fetch(struct trace_context *tc, int *nrecords);
+void hwt_procexit(pid_t pid, int status);
+int hwt_get_offs(struct trace_context *tc, size_t *offs);
+void hwt_sleep(void);
+int hwt_elf_count_libs(const char *elf_path, uint32_t *nlibs0);
+int hwt_find_sym(struct trace_context *tc);
+int hwt_start_tracing(struct trace_context *tc);
+int hwt_mmap_received(struct trace_context *tc,
+ struct hwt_record_user_entry *entry);
+
+#endif /* !_HWTVAR_H_ */
Index: usr.sbin/hwt/libpmcstat_stubs.h
===================================================================
--- /dev/null
+++ usr.sbin/hwt/libpmcstat_stubs.h
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * 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$
+ */
+
+#include <sys/types.h>
+#include <machine/profile.h>
+
+/* These are stubs, needed for compilation only. */
+
+#ifndef _HWT_LIBPMCSTAT_STUBS_H_
+#define _HWT_LIBPMCSTAT_STUBS_H_
+
+enum pmc_mode {
+ PMC_MODE_INVALID,
+};
+
+typedef int pmc_id_t;
+typedef int pmc_value_t;
+
+struct pmclog_ev;
+
+int pmclog_read(void *cookie __unused, struct pmclog_ev *ev __unused);
+int pmc_close_logfile(void);
+int pmc_attach(pmc_id_t pmc __unused, pid_t pid __unused);
+
+#endif /* !_HWT_LIBPMCSTAT_STUBS_H_ */
Index: usr.sbin/hwt/libpmcstat_stubs.c
===================================================================
--- /dev/null
+++ usr.sbin/hwt/libpmcstat_stubs.c
@@ -0,0 +1,58 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * 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 "libpmcstat_stubs.h"
+#include <libpmcstat.h>
+
+/* This is a stub file, needed for compilation only. */
+
+struct pmcstat_pmcs pmcstat_pmcs;
+struct pmcstat_process_hash_list pmcstat_process_hash[PMCSTAT_NHASH];
+
+int
+pmclog_read(void *cookie __unused, struct pmclog_ev *ev __unused)
+{
+
+ return (-1);
+}
+
+int
+pmc_close_logfile(void)
+{
+
+ return (-1);
+}
+
+int
+pmc_attach(pmc_id_t pmc __unused, pid_t pid __unused)
+{
+
+ return (-1);
+}

File Metadata

Mime Type
text/plain
Expires
Thu, Nov 7, 5:45 AM (21 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14505405
Default Alt Text
D40728.id125098.diff (64 KB)

Event Timeline