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>
18 #include <internal/lib.h> // page_size
21 #define MAXSRCCACHE (32*1024*1024)
22 #define MAXSRCFILES 64
23 #define SRC_HTAB_SZ 64
26 struct hlist_node hash_nd
;
35 static struct hlist_head srcfile_htab
[SRC_HTAB_SZ
];
36 static LIST_HEAD(srcfile_list
);
37 static long map_total_sz
;
38 static int num_srcfiles
;
40 static int countlines(char *map
, int maplen
)
43 char *end
= map
+ maplen
;
49 while (p
< end
&& (p
= memchr(p
, '\n', end
- p
)) != NULL
) {
58 static void fill_lines(char **lines
, int maxline
, char *map
, int maplen
)
61 char *end
= map
+ maplen
;
64 if (maplen
== 0 || maxline
== 0)
68 while (p
< end
&& (p
= memchr(p
, '\n', end
- p
)) != NULL
) {
77 static void free_srcfile(struct srcfile
*sf
)
79 list_del_init(&sf
->nd
);
80 hlist_del(&sf
->hash_nd
);
81 map_total_sz
-= sf
->maplen
;
82 munmap(sf
->map
, sf
->maplen
);
89 static struct srcfile
*find_srcfile(char *fn
)
95 unsigned hval
= shash((unsigned char *)fn
) % SRC_HTAB_SZ
;
97 hlist_for_each_entry (h
, &srcfile_htab
[hval
], hash_nd
) {
98 if (!strcmp(fn
, h
->fn
)) {
101 list_add(&h
->nd
, &srcfile_list
);
106 /* Only prune if there is more than one entry */
107 while ((num_srcfiles
> MAXSRCFILES
|| map_total_sz
> MAXSRCCACHE
) &&
108 srcfile_list
.next
!= &srcfile_list
) {
109 assert(!list_empty(&srcfile_list
));
110 h
= list_entry(srcfile_list
.prev
, struct srcfile
, nd
);
114 fd
= open(fn
, O_RDONLY
);
115 if (fd
< 0 || fstat(fd
, &st
) < 0) {
116 pr_debug("cannot open source file %s\n", fn
);
120 h
= malloc(sizeof(struct srcfile
));
128 h
->maplen
= st
.st_size
;
129 sz
= (h
->maplen
+ page_size
- 1) & ~(page_size
- 1);
130 h
->map
= mmap(NULL
, sz
, PROT_READ
, MAP_SHARED
, fd
, 0);
132 if (h
->map
== (char *)-1) {
133 pr_debug("cannot mmap source file %s\n", fn
);
136 h
->numlines
= countlines(h
->map
, h
->maplen
);
137 h
->lines
= calloc(h
->numlines
, sizeof(char *));
140 fill_lines(h
->lines
, h
->numlines
, h
->map
, h
->maplen
);
141 list_add(&h
->nd
, &srcfile_list
);
142 hlist_add_head(&h
->hash_nd
, &srcfile_htab
[hval
]);
143 map_total_sz
+= h
->maplen
;
156 /* Result is not 0 terminated */
157 char *find_sourceline(char *fn
, unsigned line
, int *lenp
)
160 struct srcfile
*sf
= find_srcfile(fn
);
164 if (line
>= sf
->numlines
)
169 p
= memchr(l
, '\n', sf
->map
+ sf
->maplen
- l
);