brintos

brintos / linux-shallow public Read only

0
0
Text · 3.4 KiB · 476e998 Raw
172 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Manage printing of source lines4 * Copyright (c) 2017, Intel Corporation.5 * Author: Andi Kleen6 */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_size19#include "fncache.h"20 21#define MAXSRCCACHE (32*1024*1024)22#define MAXSRCFILES     6423#define SRC_HTAB_SZ	6424 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}172