2 * Manage printing of source lines
3 * Copyright (c) 2017, Intel Corporation.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 #include "linux/list.h"
27 #define MAXSRCCACHE (32*1024*1024)
28 #define MAXSRCFILES 64
29 #define SRC_HTAB_SZ 64
32 struct hlist_node hash_nd
;
41 static struct hlist_head srcfile_htab
[SRC_HTAB_SZ
];
42 static LIST_HEAD(srcfile_list
);
43 static long map_total_sz
;
44 static int num_srcfiles
;
46 static unsigned shash(unsigned char *s
)
54 static int countlines(char *map
, int maplen
)
57 char *end
= map
+ maplen
;
63 while (p
< end
&& (p
= memchr(p
, '\n', end
- p
)) != NULL
) {
72 static void fill_lines(char **lines
, int maxline
, char *map
, int maplen
)
75 char *end
= map
+ maplen
;
78 if (maplen
== 0 || maxline
== 0)
82 while (p
< end
&& (p
= memchr(p
, '\n', end
- p
)) != NULL
) {
91 static void free_srcfile(struct srcfile
*sf
)
94 hlist_del(&sf
->hash_nd
);
95 map_total_sz
-= sf
->maplen
;
96 munmap(sf
->map
, sf
->maplen
);
103 static struct srcfile
*find_srcfile(char *fn
)
109 unsigned hval
= shash((unsigned char *)fn
) % SRC_HTAB_SZ
;
111 hlist_for_each_entry (h
, &srcfile_htab
[hval
], hash_nd
) {
112 if (!strcmp(fn
, h
->fn
)) {
115 list_add(&h
->nd
, &srcfile_list
);
120 /* Only prune if there is more than one entry */
121 while ((num_srcfiles
> MAXSRCFILES
|| map_total_sz
> MAXSRCCACHE
) &&
122 srcfile_list
.next
!= &srcfile_list
) {
123 assert(!list_empty(&srcfile_list
));
124 h
= list_entry(srcfile_list
.prev
, struct srcfile
, nd
);
128 fd
= open(fn
, O_RDONLY
);
129 if (fd
< 0 || fstat(fd
, &st
) < 0) {
130 pr_debug("cannot open source file %s\n", fn
);
134 h
= malloc(sizeof(struct srcfile
));
142 h
->maplen
= st
.st_size
;
143 sz
= (h
->maplen
+ page_size
- 1) & ~(page_size
- 1);
144 h
->map
= mmap(NULL
, sz
, PROT_READ
, MAP_SHARED
, fd
, 0);
146 if (h
->map
== (char *)-1) {
147 pr_debug("cannot mmap source file %s\n", fn
);
150 h
->numlines
= countlines(h
->map
, h
->maplen
);
151 h
->lines
= calloc(h
->numlines
, sizeof(char *));
154 fill_lines(h
->lines
, h
->numlines
, h
->map
, h
->maplen
);
155 list_add(&h
->nd
, &srcfile_list
);
156 hlist_add_head(&h
->hash_nd
, &srcfile_htab
[hval
]);
157 map_total_sz
+= h
->maplen
;
170 /* Result is not 0 terminated */
171 char *find_sourceline(char *fn
, unsigned line
, int *lenp
)
174 struct srcfile
*sf
= find_srcfile(fn
);
178 if (line
>= sf
->numlines
)
183 p
= memchr(l
, '\n', sf
->map
+ sf
->maplen
- l
);