0001
0002
0003
0004
0005
0006
0007 #include <linux/list.h>
0008 #include <linux/zalloc.h>
0009 #include <stdlib.h>
0010 #include <sys/mman.h>
0011 #include <sys/stat.h>
0012 #include <fcntl.h>
0013 #include <unistd.h>
0014 #include <assert.h>
0015 #include <string.h>
0016 #include "srccode.h"
0017 #include "debug.h"
0018 #include <internal/lib.h> // page_size
0019 #include "fncache.h"
0020
0021 #define MAXSRCCACHE (32*1024*1024)
0022 #define MAXSRCFILES 64
0023 #define SRC_HTAB_SZ 64
0024
0025 struct srcfile {
0026 struct hlist_node hash_nd;
0027 struct list_head nd;
0028 char *fn;
0029 char **lines;
0030 char *map;
0031 unsigned numlines;
0032 size_t maplen;
0033 };
0034
0035 static struct hlist_head srcfile_htab[SRC_HTAB_SZ];
0036 static LIST_HEAD(srcfile_list);
0037 static long map_total_sz;
0038 static int num_srcfiles;
0039
0040 static int countlines(char *map, int maplen)
0041 {
0042 int numl;
0043 char *end = map + maplen;
0044 char *p = map;
0045
0046 if (maplen == 0)
0047 return 0;
0048 numl = 0;
0049 while (p < end && (p = memchr(p, '\n', end - p)) != NULL) {
0050 numl++;
0051 p++;
0052 }
0053 if (p < end)
0054 numl++;
0055 return numl;
0056 }
0057
0058 static void fill_lines(char **lines, int maxline, char *map, int maplen)
0059 {
0060 int l;
0061 char *end = map + maplen;
0062 char *p = map;
0063
0064 if (maplen == 0 || maxline == 0)
0065 return;
0066 l = 0;
0067 lines[l++] = map;
0068 while (p < end && (p = memchr(p, '\n', end - p)) != NULL) {
0069 if (l >= maxline)
0070 return;
0071 lines[l++] = ++p;
0072 }
0073 if (p < end)
0074 lines[l] = p;
0075 }
0076
0077 static void free_srcfile(struct srcfile *sf)
0078 {
0079 list_del_init(&sf->nd);
0080 hlist_del(&sf->hash_nd);
0081 map_total_sz -= sf->maplen;
0082 munmap(sf->map, sf->maplen);
0083 zfree(&sf->lines);
0084 zfree(&sf->fn);
0085 free(sf);
0086 num_srcfiles--;
0087 }
0088
0089 static struct srcfile *find_srcfile(char *fn)
0090 {
0091 struct stat st;
0092 struct srcfile *h;
0093 int fd;
0094 unsigned long sz;
0095 unsigned hval = shash((unsigned char *)fn) % SRC_HTAB_SZ;
0096
0097 hlist_for_each_entry (h, &srcfile_htab[hval], hash_nd) {
0098 if (!strcmp(fn, h->fn)) {
0099
0100 list_move(&h->nd, &srcfile_list);
0101 return h;
0102 }
0103 }
0104
0105
0106 while ((num_srcfiles > MAXSRCFILES || map_total_sz > MAXSRCCACHE) &&
0107 srcfile_list.next != &srcfile_list) {
0108 assert(!list_empty(&srcfile_list));
0109 h = list_entry(srcfile_list.prev, struct srcfile, nd);
0110 free_srcfile(h);
0111 }
0112
0113 fd = open(fn, O_RDONLY);
0114 if (fd < 0 || fstat(fd, &st) < 0) {
0115 pr_debug("cannot open source file %s\n", fn);
0116 return NULL;
0117 }
0118
0119 h = malloc(sizeof(struct srcfile));
0120 if (!h)
0121 return NULL;
0122
0123 h->fn = strdup(fn);
0124 if (!h->fn)
0125 goto out_h;
0126
0127 h->maplen = st.st_size;
0128 sz = (h->maplen + page_size - 1) & ~(page_size - 1);
0129 h->map = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
0130 close(fd);
0131 if (h->map == (char *)-1) {
0132 pr_debug("cannot mmap source file %s\n", fn);
0133 goto out_fn;
0134 }
0135 h->numlines = countlines(h->map, h->maplen);
0136 h->lines = calloc(h->numlines, sizeof(char *));
0137 if (!h->lines)
0138 goto out_map;
0139 fill_lines(h->lines, h->numlines, h->map, h->maplen);
0140 list_add(&h->nd, &srcfile_list);
0141 hlist_add_head(&h->hash_nd, &srcfile_htab[hval]);
0142 map_total_sz += h->maplen;
0143 num_srcfiles++;
0144 return h;
0145
0146 out_map:
0147 munmap(h->map, sz);
0148 out_fn:
0149 zfree(&h->fn);
0150 out_h:
0151 free(h);
0152 return NULL;
0153 }
0154
0155
0156 char *find_sourceline(char *fn, unsigned line, int *lenp)
0157 {
0158 char *l, *p;
0159 struct srcfile *sf = find_srcfile(fn);
0160 if (!sf)
0161 return NULL;
0162 line--;
0163 if (line >= sf->numlines)
0164 return NULL;
0165 l = sf->lines[line];
0166 if (!l)
0167 return NULL;
0168 p = memchr(l, '\n', sf->map + sf->maplen - l);
0169 *lenp = p - l;
0170 return l;
0171 }