symbols.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/compiler.h>
  3. #include <linux/string.h>
  4. #include <sys/mman.h>
  5. #include <limits.h>
  6. #include "debug.h"
  7. #include "dso.h"
  8. #include "env.h"
  9. #include "machine.h"
  10. #include "thread.h"
  11. #include "symbol.h"
  12. #include "map.h"
  13. #include "util.h"
  14. #include "tests.h"
  15. struct test_info {
  16. struct perf_env host_env;
  17. struct machine *machine;
  18. struct thread *thread;
  19. };
  20. static int init_test_info(struct test_info *ti)
  21. {
  22. perf_env__init(&ti->host_env);
  23. ti->machine = machine__new_host(&ti->host_env);
  24. if (!ti->machine) {
  25. pr_debug("machine__new_host() failed!\n");
  26. perf_env__exit(&ti->host_env);
  27. return TEST_FAIL;
  28. }
  29. /* Create a dummy thread */
  30. ti->thread = machine__findnew_thread(ti->machine, 100, 100);
  31. if (!ti->thread) {
  32. pr_debug("machine__findnew_thread() failed!\n");
  33. perf_env__exit(&ti->host_env);
  34. return TEST_FAIL;
  35. }
  36. return TEST_OK;
  37. }
  38. static void exit_test_info(struct test_info *ti)
  39. {
  40. thread__put(ti->thread);
  41. machine__delete(ti->machine);
  42. perf_env__exit(&ti->host_env);
  43. }
  44. struct dso_map {
  45. struct dso *dso;
  46. struct map *map;
  47. };
  48. static int find_map_cb(struct map *map, void *d)
  49. {
  50. struct dso_map *data = d;
  51. if (map__dso(map) != data->dso)
  52. return 0;
  53. data->map = map;
  54. return 1;
  55. }
  56. static struct map *find_module_map(struct machine *machine, struct dso *dso)
  57. {
  58. struct dso_map data = { .dso = dso };
  59. machine__for_each_kernel_map(machine, find_map_cb, &data);
  60. return data.map;
  61. }
  62. static void get_test_dso_filename(char *filename, size_t max_sz)
  63. {
  64. if (dso_to_test)
  65. strlcpy(filename, dso_to_test, max_sz);
  66. else
  67. perf_exe(filename, max_sz);
  68. }
  69. static int create_map(struct test_info *ti, char *filename, struct map **map_p)
  70. {
  71. struct dso *dso = machine__findnew_dso(ti->machine, filename);
  72. /*
  73. * If 'filename' matches a current kernel module, must use a kernel
  74. * map. Find the one that already exists.
  75. */
  76. if (dso && dso__kernel(dso) != DSO_SPACE__USER) {
  77. *map_p = find_module_map(ti->machine, dso);
  78. dso__put(dso);
  79. if (!*map_p) {
  80. pr_debug("Failed to find map for current kernel module %s",
  81. filename);
  82. return TEST_FAIL;
  83. }
  84. map__get(*map_p);
  85. return TEST_OK;
  86. }
  87. dso__put(dso);
  88. /* Create a dummy map at 0x100000 */
  89. *map_p = map__new(ti->machine, 0x100000, 0xffffffff, 0, &dso_id_empty,
  90. PROT_EXEC, /*flags=*/0, filename, ti->thread);
  91. if (!*map_p) {
  92. pr_debug("Failed to create map!");
  93. return TEST_FAIL;
  94. }
  95. return TEST_OK;
  96. }
  97. static int test_dso(struct dso *dso)
  98. {
  99. struct symbol *last_sym = NULL;
  100. struct rb_node *nd;
  101. int ret = TEST_OK;
  102. /* dso__fprintf() prints all the symbols */
  103. if (verbose > 1)
  104. dso__fprintf(dso, stderr);
  105. for (nd = rb_first_cached(dso__symbols(dso)); nd; nd = rb_next(nd)) {
  106. struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
  107. if (sym->type != STT_FUNC && sym->type != STT_GNU_IFUNC)
  108. continue;
  109. /* Check for overlapping function symbols */
  110. if (last_sym && sym->start < last_sym->end) {
  111. pr_debug("Overlapping symbols:\n");
  112. symbol__fprintf(last_sym, stderr);
  113. symbol__fprintf(sym, stderr);
  114. ret = TEST_FAIL;
  115. }
  116. /* Check for zero-length function symbol */
  117. if (sym->start == sym->end) {
  118. pr_debug("Zero-length symbol:\n");
  119. symbol__fprintf(sym, stderr);
  120. ret = TEST_FAIL;
  121. }
  122. last_sym = sym;
  123. }
  124. return ret;
  125. }
  126. static int subdivided_dso_cb(struct dso *dso, struct machine *machine __maybe_unused, void *d)
  127. {
  128. struct dso *text_dso = d;
  129. if (dso != text_dso && strstarts(dso__short_name(dso), dso__short_name(text_dso)))
  130. if (test_dso(dso) != TEST_OK)
  131. return -1;
  132. return 0;
  133. }
  134. static int process_subdivided_dso(struct machine *machine, struct dso *dso)
  135. {
  136. int ret;
  137. ret = machine__for_each_dso(machine, subdivided_dso_cb, dso);
  138. return ret < 0 ? TEST_FAIL : TEST_OK;
  139. }
  140. static int test_file(struct test_info *ti, char *filename)
  141. {
  142. struct map *map = NULL;
  143. int ret, nr;
  144. struct dso *dso;
  145. pr_debug("Testing %s\n", filename);
  146. ret = create_map(ti, filename, &map);
  147. if (ret != TEST_OK)
  148. return ret;
  149. dso = map__dso(map);
  150. nr = dso__load(dso, map);
  151. if (nr < 0) {
  152. pr_debug("dso__load() failed!\n");
  153. ret = TEST_FAIL;
  154. goto out_put;
  155. }
  156. if (nr == 0) {
  157. pr_debug("DSO has no symbols!\n");
  158. ret = TEST_SKIP;
  159. goto out_put;
  160. }
  161. ret = test_dso(dso);
  162. /* Module dso is split into many dsos by section */
  163. if (ret == TEST_OK && dso__kernel(dso) != DSO_SPACE__USER)
  164. ret = process_subdivided_dso(ti->machine, dso);
  165. out_put:
  166. map__put(map);
  167. return ret;
  168. }
  169. static int test__symbols(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
  170. {
  171. char filename[PATH_MAX];
  172. struct test_info ti;
  173. int ret;
  174. ret = init_test_info(&ti);
  175. if (ret != TEST_OK)
  176. return ret;
  177. get_test_dso_filename(filename, sizeof(filename));
  178. ret = test_file(&ti, filename);
  179. exit_test_info(&ti);
  180. return ret;
  181. }
  182. DEFINE_SUITE("Symbols", symbols);