cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

trace_helpers.c (4356B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <ctype.h>
      3#include <stdio.h>
      4#include <stdlib.h>
      5#include <string.h>
      6#include <assert.h>
      7#include <errno.h>
      8#include <fcntl.h>
      9#include <poll.h>
     10#include <unistd.h>
     11#include <linux/perf_event.h>
     12#include <sys/mman.h>
     13#include "trace_helpers.h"
     14
     15#define DEBUGFS "/sys/kernel/debug/tracing/"
     16
     17#define MAX_SYMS 300000
     18static struct ksym syms[MAX_SYMS];
     19static int sym_cnt;
     20
     21static int ksym_cmp(const void *p1, const void *p2)
     22{
     23	return ((struct ksym *)p1)->addr - ((struct ksym *)p2)->addr;
     24}
     25
     26int load_kallsyms(void)
     27{
     28	FILE *f;
     29	char func[256], buf[256];
     30	char symbol;
     31	void *addr;
     32	int i = 0;
     33
     34	/*
     35	 * This is called/used from multiplace places,
     36	 * load symbols just once.
     37	 */
     38	if (sym_cnt)
     39		return 0;
     40
     41	f = fopen("/proc/kallsyms", "r");
     42	if (!f)
     43		return -ENOENT;
     44
     45	while (fgets(buf, sizeof(buf), f)) {
     46		if (sscanf(buf, "%p %c %s", &addr, &symbol, func) != 3)
     47			break;
     48		if (!addr)
     49			continue;
     50		syms[i].addr = (long) addr;
     51		syms[i].name = strdup(func);
     52		i++;
     53	}
     54	fclose(f);
     55	sym_cnt = i;
     56	qsort(syms, sym_cnt, sizeof(struct ksym), ksym_cmp);
     57	return 0;
     58}
     59
     60struct ksym *ksym_search(long key)
     61{
     62	int start = 0, end = sym_cnt;
     63	int result;
     64
     65	/* kallsyms not loaded. return NULL */
     66	if (sym_cnt <= 0)
     67		return NULL;
     68
     69	while (start < end) {
     70		size_t mid = start + (end - start) / 2;
     71
     72		result = key - syms[mid].addr;
     73		if (result < 0)
     74			end = mid;
     75		else if (result > 0)
     76			start = mid + 1;
     77		else
     78			return &syms[mid];
     79	}
     80
     81	if (start >= 1 && syms[start - 1].addr < key &&
     82	    key < syms[start].addr)
     83		/* valid ksym */
     84		return &syms[start - 1];
     85
     86	/* out of range. return _stext */
     87	return &syms[0];
     88}
     89
     90long ksym_get_addr(const char *name)
     91{
     92	int i;
     93
     94	for (i = 0; i < sym_cnt; i++) {
     95		if (strcmp(syms[i].name, name) == 0)
     96			return syms[i].addr;
     97	}
     98
     99	return 0;
    100}
    101
    102/* open kallsyms and read symbol addresses on the fly. Without caching all symbols,
    103 * this is faster than load + find.
    104 */
    105int kallsyms_find(const char *sym, unsigned long long *addr)
    106{
    107	char type, name[500];
    108	unsigned long long value;
    109	int err = 0;
    110	FILE *f;
    111
    112	f = fopen("/proc/kallsyms", "r");
    113	if (!f)
    114		return -EINVAL;
    115
    116	while (fscanf(f, "%llx %c %499s%*[^\n]\n", &value, &type, name) > 0) {
    117		if (strcmp(name, sym) == 0) {
    118			*addr = value;
    119			goto out;
    120		}
    121	}
    122	err = -ENOENT;
    123
    124out:
    125	fclose(f);
    126	return err;
    127}
    128
    129void read_trace_pipe(void)
    130{
    131	int trace_fd;
    132
    133	trace_fd = open(DEBUGFS "trace_pipe", O_RDONLY, 0);
    134	if (trace_fd < 0)
    135		return;
    136
    137	while (1) {
    138		static char buf[4096];
    139		ssize_t sz;
    140
    141		sz = read(trace_fd, buf, sizeof(buf) - 1);
    142		if (sz > 0) {
    143			buf[sz] = 0;
    144			puts(buf);
    145		}
    146	}
    147}
    148
    149ssize_t get_uprobe_offset(const void *addr)
    150{
    151	size_t start, end, base;
    152	char buf[256];
    153	bool found = false;
    154	FILE *f;
    155
    156	f = fopen("/proc/self/maps", "r");
    157	if (!f)
    158		return -errno;
    159
    160	while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &base) == 4) {
    161		if (buf[2] == 'x' && (uintptr_t)addr >= start && (uintptr_t)addr < end) {
    162			found = true;
    163			break;
    164		}
    165	}
    166
    167	fclose(f);
    168
    169	if (!found)
    170		return -ESRCH;
    171
    172#if defined(__powerpc64__) && defined(_CALL_ELF) && _CALL_ELF == 2
    173
    174#define OP_RT_RA_MASK   0xffff0000UL
    175#define LIS_R2          0x3c400000UL
    176#define ADDIS_R2_R12    0x3c4c0000UL
    177#define ADDI_R2_R2      0x38420000UL
    178
    179	/*
    180	 * A PPC64 ABIv2 function may have a local and a global entry
    181	 * point. We need to use the local entry point when patching
    182	 * functions, so identify and step over the global entry point
    183	 * sequence.
    184	 *
    185	 * The global entry point sequence is always of the form:
    186	 *
    187	 * addis r2,r12,XXXX
    188	 * addi  r2,r2,XXXX
    189	 *
    190	 * A linker optimisation may convert the addis to lis:
    191	 *
    192	 * lis   r2,XXXX
    193	 * addi  r2,r2,XXXX
    194	 */
    195	{
    196		const u32 *insn = (const u32 *)(uintptr_t)addr;
    197
    198		if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) ||
    199		     ((*insn & OP_RT_RA_MASK) == LIS_R2)) &&
    200		    ((*(insn + 1) & OP_RT_RA_MASK) == ADDI_R2_R2))
    201			return (uintptr_t)(insn + 2) - start + base;
    202	}
    203#endif
    204	return (uintptr_t)addr - start + base;
    205}
    206
    207ssize_t get_rel_offset(uintptr_t addr)
    208{
    209	size_t start, end, offset;
    210	char buf[256];
    211	FILE *f;
    212
    213	f = fopen("/proc/self/maps", "r");
    214	if (!f)
    215		return -errno;
    216
    217	while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &offset) == 4) {
    218		if (addr >= start && addr < end) {
    219			fclose(f);
    220			return (size_t)addr - start + offset;
    221		}
    222	}
    223
    224	fclose(f);
    225	return -EINVAL;
    226}