bpf-utils.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
  2. #ifndef _GNU_SOURCE
  3. #define _GNU_SOURCE
  4. #endif
  5. #include <errno.h>
  6. #include <stdlib.h>
  7. #include <linux/err.h>
  8. #include <linux/kernel.h>
  9. #include <bpf/bpf.h>
  10. #include "bpf-utils.h"
  11. #include "debug.h"
  12. struct bpil_array_desc {
  13. int array_offset; /* e.g. offset of jited_prog_insns */
  14. int count_offset; /* e.g. offset of jited_prog_len */
  15. int size_offset; /* > 0: offset of rec size,
  16. * < 0: fix size of -size_offset
  17. */
  18. };
  19. static const struct bpil_array_desc bpil_array_desc[] = {
  20. [PERF_BPIL_JITED_INSNS] = {
  21. offsetof(struct bpf_prog_info, jited_prog_insns),
  22. offsetof(struct bpf_prog_info, jited_prog_len),
  23. -1,
  24. },
  25. [PERF_BPIL_XLATED_INSNS] = {
  26. offsetof(struct bpf_prog_info, xlated_prog_insns),
  27. offsetof(struct bpf_prog_info, xlated_prog_len),
  28. -1,
  29. },
  30. [PERF_BPIL_MAP_IDS] = {
  31. offsetof(struct bpf_prog_info, map_ids),
  32. offsetof(struct bpf_prog_info, nr_map_ids),
  33. -(int)sizeof(__u32),
  34. },
  35. [PERF_BPIL_JITED_KSYMS] = {
  36. offsetof(struct bpf_prog_info, jited_ksyms),
  37. offsetof(struct bpf_prog_info, nr_jited_ksyms),
  38. -(int)sizeof(__u64),
  39. },
  40. [PERF_BPIL_JITED_FUNC_LENS] = {
  41. offsetof(struct bpf_prog_info, jited_func_lens),
  42. offsetof(struct bpf_prog_info, nr_jited_func_lens),
  43. -(int)sizeof(__u32),
  44. },
  45. [PERF_BPIL_FUNC_INFO] = {
  46. offsetof(struct bpf_prog_info, func_info),
  47. offsetof(struct bpf_prog_info, nr_func_info),
  48. offsetof(struct bpf_prog_info, func_info_rec_size),
  49. },
  50. [PERF_BPIL_LINE_INFO] = {
  51. offsetof(struct bpf_prog_info, line_info),
  52. offsetof(struct bpf_prog_info, nr_line_info),
  53. offsetof(struct bpf_prog_info, line_info_rec_size),
  54. },
  55. [PERF_BPIL_JITED_LINE_INFO] = {
  56. offsetof(struct bpf_prog_info, jited_line_info),
  57. offsetof(struct bpf_prog_info, nr_jited_line_info),
  58. offsetof(struct bpf_prog_info, jited_line_info_rec_size),
  59. },
  60. [PERF_BPIL_PROG_TAGS] = {
  61. offsetof(struct bpf_prog_info, prog_tags),
  62. offsetof(struct bpf_prog_info, nr_prog_tags),
  63. -(int)sizeof(__u8) * BPF_TAG_SIZE,
  64. },
  65. };
  66. static __u32 bpf_prog_info_read_offset_u32(struct bpf_prog_info *info,
  67. int offset)
  68. {
  69. __u32 *array = (__u32 *)info;
  70. if (offset >= 0)
  71. return array[offset / sizeof(__u32)];
  72. return -(int)offset;
  73. }
  74. static __u64 bpf_prog_info_read_offset_u64(struct bpf_prog_info *info,
  75. int offset)
  76. {
  77. __u64 *array = (__u64 *)info;
  78. if (offset >= 0)
  79. return array[offset / sizeof(__u64)];
  80. return -(int)offset;
  81. }
  82. static void bpf_prog_info_set_offset_u32(struct bpf_prog_info *info, int offset,
  83. __u32 val)
  84. {
  85. __u32 *array = (__u32 *)info;
  86. if (offset >= 0)
  87. array[offset / sizeof(__u32)] = val;
  88. }
  89. static void bpf_prog_info_set_offset_u64(struct bpf_prog_info *info, int offset,
  90. __u64 val)
  91. {
  92. __u64 *array = (__u64 *)info;
  93. if (offset >= 0)
  94. array[offset / sizeof(__u64)] = val;
  95. }
  96. struct perf_bpil *
  97. get_bpf_prog_info_linear(int fd, __u64 arrays)
  98. {
  99. struct bpf_prog_info info = {};
  100. struct perf_bpil *info_linear;
  101. __u32 info_len = sizeof(info);
  102. __u32 data_len = 0;
  103. int i, err;
  104. __u8 *ptr;
  105. if (arrays >> PERF_BPIL_LAST_ARRAY)
  106. return ERR_PTR(-EINVAL);
  107. /* step 1: get array dimensions */
  108. err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
  109. if (err) {
  110. pr_debug("can't get prog info: %m\n");
  111. return ERR_PTR(-EFAULT);
  112. }
  113. if (info.type >= __MAX_BPF_PROG_TYPE)
  114. pr_debug("%s:%d: unexpected program type %u\n", __func__, __LINE__, info.type);
  115. /* step 2: calculate total size of all arrays */
  116. for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
  117. const struct bpil_array_desc *desc = &bpil_array_desc[i];
  118. bool include_array = (arrays & (1UL << i)) > 0;
  119. __u32 count, size;
  120. /* kernel is too old to support this field */
  121. if (info_len < desc->array_offset + sizeof(__u32) ||
  122. info_len < desc->count_offset + sizeof(__u32) ||
  123. (desc->size_offset > 0 && info_len < (__u32)desc->size_offset))
  124. include_array = false;
  125. if (!include_array) {
  126. arrays &= ~(1UL << i); /* clear the bit */
  127. continue;
  128. }
  129. count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
  130. size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
  131. data_len += roundup(count * size, sizeof(__u64));
  132. }
  133. /* step 3: allocate continuous memory */
  134. info_linear = malloc(sizeof(struct perf_bpil) + data_len);
  135. if (!info_linear)
  136. return ERR_PTR(-ENOMEM);
  137. /* step 4: fill data to info_linear->info */
  138. info_linear->arrays = arrays;
  139. memset(&info_linear->info, 0, sizeof(info));
  140. ptr = info_linear->data;
  141. for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
  142. const struct bpil_array_desc *desc = &bpil_array_desc[i];
  143. __u32 count, size;
  144. if ((arrays & (1UL << i)) == 0)
  145. continue;
  146. count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
  147. size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
  148. bpf_prog_info_set_offset_u32(&info_linear->info,
  149. desc->count_offset, count);
  150. bpf_prog_info_set_offset_u32(&info_linear->info,
  151. desc->size_offset, size);
  152. assert(ptr >= info_linear->data);
  153. assert(ptr < &info_linear->data[data_len]);
  154. bpf_prog_info_set_offset_u64(&info_linear->info,
  155. desc->array_offset,
  156. ptr_to_u64(ptr));
  157. ptr += roundup(count * size, sizeof(__u64));
  158. }
  159. /* step 5: call syscall again to get required arrays */
  160. err = bpf_obj_get_info_by_fd(fd, &info_linear->info, &info_len);
  161. if (err) {
  162. pr_debug("can't get prog info: %m\n");
  163. free(info_linear);
  164. return ERR_PTR(-EFAULT);
  165. }
  166. if (info_linear->info.type >= __MAX_BPF_PROG_TYPE) {
  167. pr_debug("%s:%d: unexpected program type %u\n",
  168. __func__, __LINE__, info_linear->info.type);
  169. }
  170. /* step 6: verify the data */
  171. ptr = info_linear->data;
  172. for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
  173. const struct bpil_array_desc *desc = &bpil_array_desc[i];
  174. __u32 count1, count2, size1, size2;
  175. __u64 ptr2;
  176. if ((arrays & (1UL << i)) == 0)
  177. continue;
  178. count1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
  179. count2 = bpf_prog_info_read_offset_u32(&info_linear->info,
  180. desc->count_offset);
  181. if (count1 != count2) {
  182. pr_warning("%s: mismatch in element count %u vs %u\n", __func__, count1, count2);
  183. free(info_linear);
  184. return ERR_PTR(-ERANGE);
  185. }
  186. size1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
  187. size2 = bpf_prog_info_read_offset_u32(&info_linear->info,
  188. desc->size_offset);
  189. if (size1 != size2) {
  190. pr_warning("%s: mismatch in rec size %u vs %u\n", __func__, size1, size2);
  191. free(info_linear);
  192. return ERR_PTR(-ERANGE);
  193. }
  194. ptr2 = bpf_prog_info_read_offset_u64(&info_linear->info, desc->array_offset);
  195. if (ptr_to_u64(ptr) != ptr2) {
  196. pr_warning("%s: mismatch in array %p vs %llx\n", __func__, ptr, ptr2);
  197. free(info_linear);
  198. return ERR_PTR(-ERANGE);
  199. }
  200. ptr += roundup(count1 * size1, sizeof(__u64));
  201. }
  202. /* step 7: update info_len and data_len */
  203. info_linear->info_len = sizeof(struct bpf_prog_info);
  204. info_linear->data_len = data_len;
  205. return info_linear;
  206. }
  207. void bpil_addr_to_offs(struct perf_bpil *info_linear)
  208. {
  209. int i;
  210. for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
  211. const struct bpil_array_desc *desc = &bpil_array_desc[i];
  212. __u64 addr, offs;
  213. if ((info_linear->arrays & (1UL << i)) == 0)
  214. continue;
  215. addr = bpf_prog_info_read_offset_u64(&info_linear->info,
  216. desc->array_offset);
  217. offs = addr - ptr_to_u64(info_linear->data);
  218. bpf_prog_info_set_offset_u64(&info_linear->info,
  219. desc->array_offset, offs);
  220. }
  221. }
  222. void bpil_offs_to_addr(struct perf_bpil *info_linear)
  223. {
  224. int i;
  225. for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
  226. const struct bpil_array_desc *desc = &bpil_array_desc[i];
  227. __u64 addr, offs;
  228. if ((info_linear->arrays & (1UL << i)) == 0)
  229. continue;
  230. offs = bpf_prog_info_read_offset_u64(&info_linear->info,
  231. desc->array_offset);
  232. addr = offs + ptr_to_u64(info_linear->data);
  233. bpf_prog_info_set_offset_u64(&info_linear->info,
  234. desc->array_offset, addr);
  235. }
  236. }