1 // SPDX-License-Identifier: GPL-2.0-only
3 * Manage printing of source lines
4 * Copyright (c) 2017, Intel Corporation.
7 #include <linux/list.h>
8 #include <linux/zalloc.h>
20 #define MAXSRCCACHE (32*1024*1024)
21 #define MAXSRCFILES 64
22 #define SRC_HTAB_SZ 64
25 struct hlist_node hash_nd;
34 static struct hlist_head srcfile_htab[SRC_HTAB_SZ];
35 static LIST_HEAD(srcfile_list);
36 static long map_total_sz;
37 static int num_srcfiles;
39 static unsigned shash(unsigned char *s)
47 static int countlines(char *map, int maplen)
50 char *end = map + maplen;
56 while (p < end && (p = memchr(p, '\n', end - p)) != NULL) {
65 static void fill_lines(char **lines, int maxline, char *map, int maplen)
68 char *end = map + maplen;
71 if (maplen == 0 || maxline == 0)
75 while (p < end && (p = memchr(p, '\n', end - p)) != NULL) {
84 static void free_srcfile(struct srcfile *sf)
86 list_del_init(&sf->nd);
87 hlist_del(&sf->hash_nd);
88 map_total_sz -= sf->maplen;
89 munmap(sf->map, sf->maplen);
96 static struct srcfile *find_srcfile(char *fn)
102 unsigned hval = shash((unsigned char *)fn) % SRC_HTAB_SZ;
104 hlist_for_each_entry (h, &srcfile_htab[hval], hash_nd) {
105 if (!strcmp(fn, h->fn)) {
108 list_add(&h->nd, &srcfile_list);
113 /* Only prune if there is more than one entry */
114 while ((num_srcfiles > MAXSRCFILES || map_total_sz > MAXSRCCACHE) &&
115 srcfile_list.next != &srcfile_list) {
116 assert(!list_empty(&srcfile_list));
117 h = list_entry(srcfile_list.prev, struct srcfile, nd);
121 fd = open(fn, O_RDONLY);
122 if (fd < 0 || fstat(fd, &st) < 0) {
123 pr_debug("cannot open source file %s\n", fn);
127 h = malloc(sizeof(struct srcfile));
135 h->maplen = st.st_size;
136 sz = (h->maplen + page_size - 1) & ~(page_size - 1);
137 h->map = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
139 if (h->map == (char *)-1) {
140 pr_debug("cannot mmap source file %s\n", fn);
143 h->numlines = countlines(h->map, h->maplen);
144 h->lines = calloc(h->numlines, sizeof(char *));
147 fill_lines(h->lines, h->numlines, h->map, h->maplen);
148 list_add(&h->nd, &srcfile_list);
149 hlist_add_head(&h->hash_nd, &srcfile_htab[hval]);
150 map_total_sz += h->maplen;
163 /* Result is not 0 terminated */
164 char *find_sourceline(char *fn, unsigned line, int *lenp)
167 struct srcfile *sf = find_srcfile(fn);
171 if (line >= sf->numlines)
176 p = memchr(l, '\n', sf->map + sf->maplen - l);