Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Manage printing of source lines
0004  * Copyright (c) 2017, Intel Corporation.
0005  * Author: Andi Kleen
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             /* Move to front */
0100             list_move(&h->nd, &srcfile_list);
0101             return h;
0102         }
0103     }
0104 
0105     /* Only prune if there is more than one entry */
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 /* Result is not 0 terminated */
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 }