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

srccode.c (3509B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Manage printing of source lines
      4 * Copyright (c) 2017, Intel Corporation.
      5 * Author: Andi Kleen
      6 */
      7#include <linux/list.h>
      8#include <linux/zalloc.h>
      9#include <stdlib.h>
     10#include <sys/mman.h>
     11#include <sys/stat.h>
     12#include <fcntl.h>
     13#include <unistd.h>
     14#include <assert.h>
     15#include <string.h>
     16#include "srccode.h"
     17#include "debug.h"
     18#include <internal/lib.h> // page_size
     19#include "fncache.h"
     20
     21#define MAXSRCCACHE (32*1024*1024)
     22#define MAXSRCFILES     64
     23#define SRC_HTAB_SZ	64
     24
     25struct srcfile {
     26	struct hlist_node hash_nd;
     27	struct list_head nd;
     28	char *fn;
     29	char **lines;
     30	char *map;
     31	unsigned numlines;
     32	size_t maplen;
     33};
     34
     35static struct hlist_head srcfile_htab[SRC_HTAB_SZ];
     36static LIST_HEAD(srcfile_list);
     37static long map_total_sz;
     38static int num_srcfiles;
     39
     40static int countlines(char *map, int maplen)
     41{
     42	int numl;
     43	char *end = map + maplen;
     44	char *p = map;
     45
     46	if (maplen == 0)
     47		return 0;
     48	numl = 0;
     49	while (p < end && (p = memchr(p, '\n', end - p)) != NULL) {
     50		numl++;
     51		p++;
     52	}
     53	if (p < end)
     54		numl++;
     55	return numl;
     56}
     57
     58static void fill_lines(char **lines, int maxline, char *map, int maplen)
     59{
     60	int l;
     61	char *end = map + maplen;
     62	char *p = map;
     63
     64	if (maplen == 0 || maxline == 0)
     65		return;
     66	l = 0;
     67	lines[l++] = map;
     68	while (p < end && (p = memchr(p, '\n', end - p)) != NULL) {
     69		if (l >= maxline)
     70			return;
     71		lines[l++] = ++p;
     72	}
     73	if (p < end)
     74		lines[l] = p;
     75}
     76
     77static void free_srcfile(struct srcfile *sf)
     78{
     79	list_del_init(&sf->nd);
     80	hlist_del(&sf->hash_nd);
     81	map_total_sz -= sf->maplen;
     82	munmap(sf->map, sf->maplen);
     83	zfree(&sf->lines);
     84	zfree(&sf->fn);
     85	free(sf);
     86	num_srcfiles--;
     87}
     88
     89static struct srcfile *find_srcfile(char *fn)
     90{
     91	struct stat st;
     92	struct srcfile *h;
     93	int fd;
     94	unsigned long sz;
     95	unsigned hval = shash((unsigned char *)fn) % SRC_HTAB_SZ;
     96
     97	hlist_for_each_entry (h, &srcfile_htab[hval], hash_nd) {
     98		if (!strcmp(fn, h->fn)) {
     99			/* Move to front */
    100			list_move(&h->nd, &srcfile_list);
    101			return h;
    102		}
    103	}
    104
    105	/* Only prune if there is more than one entry */
    106	while ((num_srcfiles > MAXSRCFILES || map_total_sz > MAXSRCCACHE) &&
    107	       srcfile_list.next != &srcfile_list) {
    108		assert(!list_empty(&srcfile_list));
    109		h = list_entry(srcfile_list.prev, struct srcfile, nd);
    110		free_srcfile(h);
    111	}
    112
    113	fd = open(fn, O_RDONLY);
    114	if (fd < 0 || fstat(fd, &st) < 0) {
    115		pr_debug("cannot open source file %s\n", fn);
    116		return NULL;
    117	}
    118
    119	h = malloc(sizeof(struct srcfile));
    120	if (!h)
    121		return NULL;
    122
    123	h->fn = strdup(fn);
    124	if (!h->fn)
    125		goto out_h;
    126
    127	h->maplen = st.st_size;
    128	sz = (h->maplen + page_size - 1) & ~(page_size - 1);
    129	h->map = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
    130	close(fd);
    131	if (h->map == (char *)-1) {
    132		pr_debug("cannot mmap source file %s\n", fn);
    133		goto out_fn;
    134	}
    135	h->numlines = countlines(h->map, h->maplen);
    136	h->lines = calloc(h->numlines, sizeof(char *));
    137	if (!h->lines)
    138		goto out_map;
    139	fill_lines(h->lines, h->numlines, h->map, h->maplen);
    140	list_add(&h->nd, &srcfile_list);
    141	hlist_add_head(&h->hash_nd, &srcfile_htab[hval]);
    142	map_total_sz += h->maplen;
    143	num_srcfiles++;
    144	return h;
    145
    146out_map:
    147	munmap(h->map, sz);
    148out_fn:
    149	zfree(&h->fn);
    150out_h:
    151	free(h);
    152	return NULL;
    153}
    154
    155/* Result is not 0 terminated */
    156char *find_sourceline(char *fn, unsigned line, int *lenp)
    157{
    158	char *l, *p;
    159	struct srcfile *sf = find_srcfile(fn);
    160	if (!sf)
    161		return NULL;
    162	line--;
    163	if (line >= sf->numlines)
    164		return NULL;
    165	l = sf->lines[line];
    166	if (!l)
    167		return NULL;
    168	p = memchr(l, '\n', sf->map + sf->maplen - l);
    169	*lenp = p - l;
    170	return l;
    171}