root/tools/perf/util/srccode.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. shash
  2. countlines
  3. fill_lines
  4. free_srcfile
  5. find_srcfile
  6. find_sourceline

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Manage printing of source lines
   4  * Copyright (c) 2017, Intel Corporation.
   5  * Author: Andi Kleen
   6  */
   7 #include <linux/list.h>
   8 #include <linux/zalloc.h>
   9 #include <stdlib.h>
  10 #include <sys/mman.h>
  11 #include <sys/stat.h>
  12 #include <fcntl.h>
  13 #include <unistd.h>
  14 #include <assert.h>
  15 #include <string.h>
  16 #include "srccode.h"
  17 #include "debug.h"
  18 #include <internal/lib.h> // page_size
  19 
  20 #define MAXSRCCACHE (32*1024*1024)
  21 #define MAXSRCFILES     64
  22 #define SRC_HTAB_SZ     64
  23 
  24 struct srcfile {
  25         struct hlist_node hash_nd;
  26         struct list_head nd;
  27         char *fn;
  28         char **lines;
  29         char *map;
  30         unsigned numlines;
  31         size_t maplen;
  32 };
  33 
  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;
  38 
  39 static unsigned shash(unsigned char *s)
  40 {
  41         unsigned h = 0;
  42         while (*s)
  43                 h = 65599 * h + *s++;
  44         return h ^ (h >> 16);
  45 }
  46 
  47 static int countlines(char *map, int maplen)
  48 {
  49         int numl;
  50         char *end = map + maplen;
  51         char *p = map;
  52 
  53         if (maplen == 0)
  54                 return 0;
  55         numl = 0;
  56         while (p < end && (p = memchr(p, '\n', end - p)) != NULL) {
  57                 numl++;
  58                 p++;
  59         }
  60         if (p < end)
  61                 numl++;
  62         return numl;
  63 }
  64 
  65 static void fill_lines(char **lines, int maxline, char *map, int maplen)
  66 {
  67         int l;
  68         char *end = map + maplen;
  69         char *p = map;
  70 
  71         if (maplen == 0 || maxline == 0)
  72                 return;
  73         l = 0;
  74         lines[l++] = map;
  75         while (p < end && (p = memchr(p, '\n', end - p)) != NULL) {
  76                 if (l >= maxline)
  77                         return;
  78                 lines[l++] = ++p;
  79         }
  80         if (p < end)
  81                 lines[l] = p;
  82 }
  83 
  84 static void free_srcfile(struct srcfile *sf)
  85 {
  86         list_del_init(&sf->nd);
  87         hlist_del(&sf->hash_nd);
  88         map_total_sz -= sf->maplen;
  89         munmap(sf->map, sf->maplen);
  90         zfree(&sf->lines);
  91         zfree(&sf->fn);
  92         free(sf);
  93         num_srcfiles--;
  94 }
  95 
  96 static struct srcfile *find_srcfile(char *fn)
  97 {
  98         struct stat st;
  99         struct srcfile *h;
 100         int fd;
 101         unsigned long sz;
 102         unsigned hval = shash((unsigned char *)fn) % SRC_HTAB_SZ;
 103 
 104         hlist_for_each_entry (h, &srcfile_htab[hval], hash_nd) {
 105                 if (!strcmp(fn, h->fn)) {
 106                         /* Move to front */
 107                         list_del(&h->nd);
 108                         list_add(&h->nd, &srcfile_list);
 109                         return h;
 110                 }
 111         }
 112 
 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);
 118                 free_srcfile(h);
 119         }
 120 
 121         fd = open(fn, O_RDONLY);
 122         if (fd < 0 || fstat(fd, &st) < 0) {
 123                 pr_debug("cannot open source file %s\n", fn);
 124                 return NULL;
 125         }
 126 
 127         h = malloc(sizeof(struct srcfile));
 128         if (!h)
 129                 return NULL;
 130 
 131         h->fn = strdup(fn);
 132         if (!h->fn)
 133                 goto out_h;
 134 
 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);
 138         close(fd);
 139         if (h->map == (char *)-1) {
 140                 pr_debug("cannot mmap source file %s\n", fn);
 141                 goto out_fn;
 142         }
 143         h->numlines = countlines(h->map, h->maplen);
 144         h->lines = calloc(h->numlines, sizeof(char *));
 145         if (!h->lines)
 146                 goto out_map;
 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;
 151         num_srcfiles++;
 152         return h;
 153 
 154 out_map:
 155         munmap(h->map, sz);
 156 out_fn:
 157         zfree(&h->fn);
 158 out_h:
 159         free(h);
 160         return NULL;
 161 }
 162 
 163 /* Result is not 0 terminated */
 164 char *find_sourceline(char *fn, unsigned line, int *lenp)
 165 {
 166         char *l, *p;
 167         struct srcfile *sf = find_srcfile(fn);
 168         if (!sf)
 169                 return NULL;
 170         line--;
 171         if (line >= sf->numlines)
 172                 return NULL;
 173         l = sf->lines[line];
 174         if (!l)
 175                 return NULL;
 176         p = memchr(l, '\n', sf->map + sf->maplen - l);
 177         *lenp = p - l;
 178         return l;
 179 }

/* [<][>][^][v][top][bottom][index][help] */