srccode.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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. #include "hashmap.h"
  20. #define MAXSRCCACHE (32*1024*1024)
  21. #define MAXSRCFILES 64
  22. #define SRC_HTAB_SZ 64
  23. struct srcfile {
  24. struct hlist_node hash_nd;
  25. struct list_head nd;
  26. char *fn;
  27. char **lines;
  28. char *map;
  29. unsigned numlines;
  30. size_t maplen;
  31. };
  32. static struct hlist_head srcfile_htab[SRC_HTAB_SZ];
  33. static LIST_HEAD(srcfile_list);
  34. static long map_total_sz;
  35. static int num_srcfiles;
  36. static int countlines(char *map, int maplen)
  37. {
  38. int numl;
  39. char *end = map + maplen;
  40. char *p = map;
  41. if (maplen == 0)
  42. return 0;
  43. numl = 0;
  44. while (p < end && (p = memchr(p, '\n', end - p)) != NULL) {
  45. numl++;
  46. p++;
  47. }
  48. if (p < end)
  49. numl++;
  50. return numl;
  51. }
  52. static void fill_lines(char **lines, int maxline, char *map, int maplen)
  53. {
  54. int l;
  55. char *end = map + maplen;
  56. char *p = map;
  57. if (maplen == 0 || maxline == 0)
  58. return;
  59. l = 0;
  60. lines[l++] = map;
  61. while (p < end && (p = memchr(p, '\n', end - p)) != NULL) {
  62. if (l >= maxline)
  63. return;
  64. lines[l++] = ++p;
  65. }
  66. if (p < end)
  67. lines[l] = p;
  68. }
  69. static void free_srcfile(struct srcfile *sf)
  70. {
  71. list_del_init(&sf->nd);
  72. hlist_del(&sf->hash_nd);
  73. map_total_sz -= sf->maplen;
  74. munmap(sf->map, sf->maplen);
  75. zfree(&sf->lines);
  76. zfree(&sf->fn);
  77. free(sf);
  78. num_srcfiles--;
  79. }
  80. static struct srcfile *find_srcfile(char *fn)
  81. {
  82. struct stat st;
  83. struct srcfile *h;
  84. int fd;
  85. unsigned long sz;
  86. size_t hval = str_hash(fn) % SRC_HTAB_SZ;
  87. hlist_for_each_entry (h, &srcfile_htab[hval], hash_nd) {
  88. if (!strcmp(fn, h->fn)) {
  89. /* Move to front */
  90. list_move(&h->nd, &srcfile_list);
  91. return h;
  92. }
  93. }
  94. /* Only prune if there is more than one entry */
  95. while ((num_srcfiles > MAXSRCFILES || map_total_sz > MAXSRCCACHE) &&
  96. srcfile_list.next != &srcfile_list) {
  97. assert(!list_empty(&srcfile_list));
  98. h = list_entry(srcfile_list.prev, struct srcfile, nd);
  99. free_srcfile(h);
  100. }
  101. fd = open(fn, O_RDONLY);
  102. if (fd < 0 || fstat(fd, &st) < 0) {
  103. pr_debug("cannot open source file %s\n", fn);
  104. return NULL;
  105. }
  106. h = malloc(sizeof(struct srcfile));
  107. if (!h)
  108. return NULL;
  109. h->fn = strdup(fn);
  110. if (!h->fn)
  111. goto out_h;
  112. h->maplen = st.st_size;
  113. sz = (h->maplen + page_size - 1) & ~(page_size - 1);
  114. h->map = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
  115. close(fd);
  116. if (h->map == (char *)-1) {
  117. pr_debug("cannot mmap source file %s\n", fn);
  118. goto out_fn;
  119. }
  120. h->numlines = countlines(h->map, h->maplen);
  121. h->lines = calloc(h->numlines, sizeof(char *));
  122. if (!h->lines)
  123. goto out_map;
  124. fill_lines(h->lines, h->numlines, h->map, h->maplen);
  125. list_add(&h->nd, &srcfile_list);
  126. hlist_add_head(&h->hash_nd, &srcfile_htab[hval]);
  127. map_total_sz += h->maplen;
  128. num_srcfiles++;
  129. return h;
  130. out_map:
  131. munmap(h->map, sz);
  132. out_fn:
  133. zfree(&h->fn);
  134. out_h:
  135. free(h);
  136. return NULL;
  137. }
  138. /* Result is not 0 terminated */
  139. char *find_sourceline(char *fn, unsigned line, int *lenp)
  140. {
  141. char *l, *p;
  142. struct srcfile *sf = find_srcfile(fn);
  143. if (!sf)
  144. return NULL;
  145. line--;
  146. if (line >= sf->numlines)
  147. return NULL;
  148. l = sf->lines[line];
  149. if (!l)
  150. return NULL;
  151. p = memchr(l, '\n', sf->map + sf->maplen - l);
  152. *lenp = p - l;
  153. return l;
  154. }