PageRenderTime 48ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/tools/bpf/bpftool/gen.c

https://bitbucket.org/mirror/linux
C | 609 lines | 537 code | 59 blank | 13 comment | 77 complexity | d587898d47d826bd4de705f8e2c9c947 MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
  2. /* Copyright (C) 2019 Facebook */
  3. #ifndef _GNU_SOURCE
  4. #define _GNU_SOURCE
  5. #endif
  6. #include <ctype.h>
  7. #include <errno.h>
  8. #include <fcntl.h>
  9. #include <linux/err.h>
  10. #include <stdbool.h>
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <unistd.h>
  14. #include <bpf/bpf.h>
  15. #include <bpf/libbpf.h>
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #include <sys/mman.h>
  19. #include <bpf/btf.h>
  20. #include "bpf/libbpf_internal.h"
  21. #include "json_writer.h"
  22. #include "main.h"
  23. #define MAX_OBJ_NAME_LEN 64
  24. static void sanitize_identifier(char *name)
  25. {
  26. int i;
  27. for (i = 0; name[i]; i++)
  28. if (!isalnum(name[i]) && name[i] != '_')
  29. name[i] = '_';
  30. }
  31. static bool str_has_suffix(const char *str, const char *suffix)
  32. {
  33. size_t i, n1 = strlen(str), n2 = strlen(suffix);
  34. if (n1 < n2)
  35. return false;
  36. for (i = 0; i < n2; i++) {
  37. if (str[n1 - i - 1] != suffix[n2 - i - 1])
  38. return false;
  39. }
  40. return true;
  41. }
  42. static void get_obj_name(char *name, const char *file)
  43. {
  44. /* Using basename() GNU version which doesn't modify arg. */
  45. strncpy(name, basename(file), MAX_OBJ_NAME_LEN - 1);
  46. name[MAX_OBJ_NAME_LEN - 1] = '\0';
  47. if (str_has_suffix(name, ".o"))
  48. name[strlen(name) - 2] = '\0';
  49. sanitize_identifier(name);
  50. }
  51. static void get_header_guard(char *guard, const char *obj_name)
  52. {
  53. int i;
  54. sprintf(guard, "__%s_SKEL_H__", obj_name);
  55. for (i = 0; guard[i]; i++)
  56. guard[i] = toupper(guard[i]);
  57. }
  58. static const char *get_map_ident(const struct bpf_map *map)
  59. {
  60. const char *name = bpf_map__name(map);
  61. if (!bpf_map__is_internal(map))
  62. return name;
  63. if (str_has_suffix(name, ".data"))
  64. return "data";
  65. else if (str_has_suffix(name, ".rodata"))
  66. return "rodata";
  67. else if (str_has_suffix(name, ".bss"))
  68. return "bss";
  69. else if (str_has_suffix(name, ".kconfig"))
  70. return "kconfig";
  71. else
  72. return NULL;
  73. }
  74. static void codegen_btf_dump_printf(void *ct, const char *fmt, va_list args)
  75. {
  76. vprintf(fmt, args);
  77. }
  78. static int codegen_datasec_def(struct bpf_object *obj,
  79. struct btf *btf,
  80. struct btf_dump *d,
  81. const struct btf_type *sec,
  82. const char *obj_name)
  83. {
  84. const char *sec_name = btf__name_by_offset(btf, sec->name_off);
  85. const struct btf_var_secinfo *sec_var = btf_var_secinfos(sec);
  86. int i, err, off = 0, pad_cnt = 0, vlen = btf_vlen(sec);
  87. const char *sec_ident;
  88. char var_ident[256];
  89. if (strcmp(sec_name, ".data") == 0)
  90. sec_ident = "data";
  91. else if (strcmp(sec_name, ".bss") == 0)
  92. sec_ident = "bss";
  93. else if (strcmp(sec_name, ".rodata") == 0)
  94. sec_ident = "rodata";
  95. else if (strcmp(sec_name, ".kconfig") == 0)
  96. sec_ident = "kconfig";
  97. else
  98. return 0;
  99. printf(" struct %s__%s {\n", obj_name, sec_ident);
  100. for (i = 0; i < vlen; i++, sec_var++) {
  101. const struct btf_type *var = btf__type_by_id(btf, sec_var->type);
  102. const char *var_name = btf__name_by_offset(btf, var->name_off);
  103. DECLARE_LIBBPF_OPTS(btf_dump_emit_type_decl_opts, opts,
  104. .field_name = var_ident,
  105. .indent_level = 2,
  106. );
  107. int need_off = sec_var->offset, align_off, align;
  108. __u32 var_type_id = var->type;
  109. const struct btf_type *t;
  110. t = btf__type_by_id(btf, var_type_id);
  111. while (btf_is_mod(t)) {
  112. var_type_id = t->type;
  113. t = btf__type_by_id(btf, var_type_id);
  114. }
  115. if (off > need_off) {
  116. p_err("Something is wrong for %s's variable #%d: need offset %d, already at %d.\n",
  117. sec_name, i, need_off, off);
  118. return -EINVAL;
  119. }
  120. align = btf__align_of(btf, var->type);
  121. if (align <= 0) {
  122. p_err("Failed to determine alignment of variable '%s': %d",
  123. var_name, align);
  124. return -EINVAL;
  125. }
  126. align_off = (off + align - 1) / align * align;
  127. if (align_off != need_off) {
  128. printf("\t\tchar __pad%d[%d];\n",
  129. pad_cnt, need_off - off);
  130. pad_cnt++;
  131. }
  132. /* sanitize variable name, e.g., for static vars inside
  133. * a function, it's name is '<function name>.<variable name>',
  134. * which we'll turn into a '<function name>_<variable name>'
  135. */
  136. var_ident[0] = '\0';
  137. strncat(var_ident, var_name, sizeof(var_ident) - 1);
  138. sanitize_identifier(var_ident);
  139. printf("\t\t");
  140. err = btf_dump__emit_type_decl(d, var_type_id, &opts);
  141. if (err)
  142. return err;
  143. printf(";\n");
  144. off = sec_var->offset + sec_var->size;
  145. }
  146. printf(" } *%s;\n", sec_ident);
  147. return 0;
  148. }
  149. static int codegen_datasecs(struct bpf_object *obj, const char *obj_name)
  150. {
  151. struct btf *btf = bpf_object__btf(obj);
  152. int n = btf__get_nr_types(btf);
  153. struct btf_dump *d;
  154. int i, err = 0;
  155. d = btf_dump__new(btf, NULL, NULL, codegen_btf_dump_printf);
  156. if (IS_ERR(d))
  157. return PTR_ERR(d);
  158. for (i = 1; i <= n; i++) {
  159. const struct btf_type *t = btf__type_by_id(btf, i);
  160. if (!btf_is_datasec(t))
  161. continue;
  162. err = codegen_datasec_def(obj, btf, d, t, obj_name);
  163. if (err)
  164. goto out;
  165. }
  166. out:
  167. btf_dump__free(d);
  168. return err;
  169. }
  170. static void codegen(const char *template, ...)
  171. {
  172. const char *src, *end;
  173. int skip_tabs = 0, n;
  174. char *s, *dst;
  175. va_list args;
  176. char c;
  177. n = strlen(template);
  178. s = malloc(n + 1);
  179. if (!s)
  180. exit(-1);
  181. src = template;
  182. dst = s;
  183. /* find out "baseline" indentation to skip */
  184. while ((c = *src++)) {
  185. if (c == '\t') {
  186. skip_tabs++;
  187. } else if (c == '\n') {
  188. break;
  189. } else {
  190. p_err("unrecognized character at pos %td in template '%s'",
  191. src - template - 1, template);
  192. free(s);
  193. exit(-1);
  194. }
  195. }
  196. while (*src) {
  197. /* skip baseline indentation tabs */
  198. for (n = skip_tabs; n > 0; n--, src++) {
  199. if (*src != '\t') {
  200. p_err("not enough tabs at pos %td in template '%s'",
  201. src - template - 1, template);
  202. free(s);
  203. exit(-1);
  204. }
  205. }
  206. /* trim trailing whitespace */
  207. end = strchrnul(src, '\n');
  208. for (n = end - src; n > 0 && isspace(src[n - 1]); n--)
  209. ;
  210. memcpy(dst, src, n);
  211. dst += n;
  212. if (*end)
  213. *dst++ = '\n';
  214. src = *end ? end + 1 : end;
  215. }
  216. *dst++ = '\0';
  217. /* print out using adjusted template */
  218. va_start(args, template);
  219. n = vprintf(s, args);
  220. va_end(args);
  221. free(s);
  222. }
  223. static int do_skeleton(int argc, char **argv)
  224. {
  225. char header_guard[MAX_OBJ_NAME_LEN + sizeof("__SKEL_H__")];
  226. size_t i, map_cnt = 0, prog_cnt = 0, file_sz, mmap_sz;
  227. DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);
  228. char obj_name[MAX_OBJ_NAME_LEN], *obj_data;
  229. struct bpf_object *obj = NULL;
  230. const char *file, *ident;
  231. struct bpf_program *prog;
  232. int fd, len, err = -1;
  233. struct bpf_map *map;
  234. struct btf *btf;
  235. struct stat st;
  236. if (!REQ_ARGS(1)) {
  237. usage();
  238. return -1;
  239. }
  240. file = GET_ARG();
  241. if (argc) {
  242. p_err("extra unknown arguments");
  243. return -1;
  244. }
  245. if (stat(file, &st)) {
  246. p_err("failed to stat() %s: %s", file, strerror(errno));
  247. return -1;
  248. }
  249. file_sz = st.st_size;
  250. mmap_sz = roundup(file_sz, sysconf(_SC_PAGE_SIZE));
  251. fd = open(file, O_RDONLY);
  252. if (fd < 0) {
  253. p_err("failed to open() %s: %s", file, strerror(errno));
  254. return -1;
  255. }
  256. obj_data = mmap(NULL, mmap_sz, PROT_READ, MAP_PRIVATE, fd, 0);
  257. if (obj_data == MAP_FAILED) {
  258. obj_data = NULL;
  259. p_err("failed to mmap() %s: %s", file, strerror(errno));
  260. goto out;
  261. }
  262. get_obj_name(obj_name, file);
  263. opts.object_name = obj_name;
  264. obj = bpf_object__open_mem(obj_data, file_sz, &opts);
  265. if (IS_ERR(obj)) {
  266. obj = NULL;
  267. p_err("failed to open BPF object file: %ld", PTR_ERR(obj));
  268. goto out;
  269. }
  270. bpf_object__for_each_map(map, obj) {
  271. ident = get_map_ident(map);
  272. if (!ident) {
  273. p_err("ignoring unrecognized internal map '%s'...",
  274. bpf_map__name(map));
  275. continue;
  276. }
  277. map_cnt++;
  278. }
  279. bpf_object__for_each_program(prog, obj) {
  280. prog_cnt++;
  281. }
  282. get_header_guard(header_guard, obj_name);
  283. codegen("\
  284. \n\
  285. /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ \n\
  286. \n\
  287. /* THIS FILE IS AUTOGENERATED! */ \n\
  288. #ifndef %2$s \n\
  289. #define %2$s \n\
  290. \n\
  291. #include <stdlib.h> \n\
  292. #include <bpf/libbpf.h> \n\
  293. \n\
  294. struct %1$s { \n\
  295. struct bpf_object_skeleton *skeleton; \n\
  296. struct bpf_object *obj; \n\
  297. ",
  298. obj_name, header_guard
  299. );
  300. if (map_cnt) {
  301. printf("\tstruct {\n");
  302. bpf_object__for_each_map(map, obj) {
  303. ident = get_map_ident(map);
  304. if (!ident)
  305. continue;
  306. printf("\t\tstruct bpf_map *%s;\n", ident);
  307. }
  308. printf("\t} maps;\n");
  309. }
  310. if (prog_cnt) {
  311. printf("\tstruct {\n");
  312. bpf_object__for_each_program(prog, obj) {
  313. printf("\t\tstruct bpf_program *%s;\n",
  314. bpf_program__name(prog));
  315. }
  316. printf("\t} progs;\n");
  317. printf("\tstruct {\n");
  318. bpf_object__for_each_program(prog, obj) {
  319. printf("\t\tstruct bpf_link *%s;\n",
  320. bpf_program__name(prog));
  321. }
  322. printf("\t} links;\n");
  323. }
  324. btf = bpf_object__btf(obj);
  325. if (btf) {
  326. err = codegen_datasecs(obj, obj_name);
  327. if (err)
  328. goto out;
  329. }
  330. codegen("\
  331. \n\
  332. }; \n\
  333. \n\
  334. static void \n\
  335. %1$s__destroy(struct %1$s *obj) \n\
  336. { \n\
  337. if (!obj) \n\
  338. return; \n\
  339. if (obj->skeleton) \n\
  340. bpf_object__destroy_skeleton(obj->skeleton);\n\
  341. free(obj); \n\
  342. } \n\
  343. \n\
  344. static inline int \n\
  345. %1$s__create_skeleton(struct %1$s *obj); \n\
  346. \n\
  347. static inline struct %1$s * \n\
  348. %1$s__open_opts(const struct bpf_object_open_opts *opts) \n\
  349. { \n\
  350. struct %1$s *obj; \n\
  351. \n\
  352. obj = (typeof(obj))calloc(1, sizeof(*obj)); \n\
  353. if (!obj) \n\
  354. return NULL; \n\
  355. if (%1$s__create_skeleton(obj)) \n\
  356. goto err; \n\
  357. if (bpf_object__open_skeleton(obj->skeleton, opts)) \n\
  358. goto err; \n\
  359. \n\
  360. return obj; \n\
  361. err: \n\
  362. %1$s__destroy(obj); \n\
  363. return NULL; \n\
  364. } \n\
  365. \n\
  366. static inline struct %1$s * \n\
  367. %1$s__open(void) \n\
  368. { \n\
  369. return %1$s__open_opts(NULL); \n\
  370. } \n\
  371. \n\
  372. static inline int \n\
  373. %1$s__load(struct %1$s *obj) \n\
  374. { \n\
  375. return bpf_object__load_skeleton(obj->skeleton); \n\
  376. } \n\
  377. \n\
  378. static inline struct %1$s * \n\
  379. %1$s__open_and_load(void) \n\
  380. { \n\
  381. struct %1$s *obj; \n\
  382. \n\
  383. obj = %1$s__open(); \n\
  384. if (!obj) \n\
  385. return NULL; \n\
  386. if (%1$s__load(obj)) { \n\
  387. %1$s__destroy(obj); \n\
  388. return NULL; \n\
  389. } \n\
  390. return obj; \n\
  391. } \n\
  392. \n\
  393. static inline int \n\
  394. %1$s__attach(struct %1$s *obj) \n\
  395. { \n\
  396. return bpf_object__attach_skeleton(obj->skeleton); \n\
  397. } \n\
  398. \n\
  399. static inline void \n\
  400. %1$s__detach(struct %1$s *obj) \n\
  401. { \n\
  402. return bpf_object__detach_skeleton(obj->skeleton); \n\
  403. } \n\
  404. ",
  405. obj_name
  406. );
  407. codegen("\
  408. \n\
  409. \n\
  410. static inline int \n\
  411. %1$s__create_skeleton(struct %1$s *obj) \n\
  412. { \n\
  413. struct bpf_object_skeleton *s; \n\
  414. \n\
  415. s = (typeof(s))calloc(1, sizeof(*s)); \n\
  416. if (!s) \n\
  417. return -1; \n\
  418. obj->skeleton = s; \n\
  419. \n\
  420. s->sz = sizeof(*s); \n\
  421. s->name = \"%1$s\"; \n\
  422. s->obj = &obj->obj; \n\
  423. ",
  424. obj_name
  425. );
  426. if (map_cnt) {
  427. codegen("\
  428. \n\
  429. \n\
  430. /* maps */ \n\
  431. s->map_cnt = %zu; \n\
  432. s->map_skel_sz = sizeof(*s->maps); \n\
  433. s->maps = (typeof(s->maps))calloc(s->map_cnt, s->map_skel_sz);\n\
  434. if (!s->maps) \n\
  435. goto err; \n\
  436. ",
  437. map_cnt
  438. );
  439. i = 0;
  440. bpf_object__for_each_map(map, obj) {
  441. ident = get_map_ident(map);
  442. if (!ident)
  443. continue;
  444. codegen("\
  445. \n\
  446. \n\
  447. s->maps[%zu].name = \"%s\"; \n\
  448. s->maps[%zu].map = &obj->maps.%s; \n\
  449. ",
  450. i, bpf_map__name(map), i, ident);
  451. /* memory-mapped internal maps */
  452. if (bpf_map__is_internal(map) &&
  453. (bpf_map__def(map)->map_flags & BPF_F_MMAPABLE)) {
  454. printf("\ts->maps[%zu].mmaped = (void **)&obj->%s;\n",
  455. i, ident);
  456. }
  457. i++;
  458. }
  459. }
  460. if (prog_cnt) {
  461. codegen("\
  462. \n\
  463. \n\
  464. /* programs */ \n\
  465. s->prog_cnt = %zu; \n\
  466. s->prog_skel_sz = sizeof(*s->progs); \n\
  467. s->progs = (typeof(s->progs))calloc(s->prog_cnt, s->prog_skel_sz);\n\
  468. if (!s->progs) \n\
  469. goto err; \n\
  470. ",
  471. prog_cnt
  472. );
  473. i = 0;
  474. bpf_object__for_each_program(prog, obj) {
  475. codegen("\
  476. \n\
  477. \n\
  478. s->progs[%1$zu].name = \"%2$s\"; \n\
  479. s->progs[%1$zu].prog = &obj->progs.%2$s;\n\
  480. s->progs[%1$zu].link = &obj->links.%2$s;\n\
  481. ",
  482. i, bpf_program__name(prog));
  483. i++;
  484. }
  485. }
  486. codegen("\
  487. \n\
  488. \n\
  489. s->data_sz = %d; \n\
  490. s->data = (void *)\"\\ \n\
  491. ",
  492. file_sz);
  493. /* embed contents of BPF object file */
  494. for (i = 0, len = 0; i < file_sz; i++) {
  495. int w = obj_data[i] ? 4 : 2;
  496. len += w;
  497. if (len > 78) {
  498. printf("\\\n");
  499. len = w;
  500. }
  501. if (!obj_data[i])
  502. printf("\\0");
  503. else
  504. printf("\\x%02x", (unsigned char)obj_data[i]);
  505. }
  506. codegen("\
  507. \n\
  508. \"; \n\
  509. \n\
  510. return 0; \n\
  511. err: \n\
  512. bpf_object__destroy_skeleton(s); \n\
  513. return -1; \n\
  514. } \n\
  515. \n\
  516. #endif /* %s */ \n\
  517. ",
  518. header_guard);
  519. err = 0;
  520. out:
  521. bpf_object__close(obj);
  522. if (obj_data)
  523. munmap(obj_data, mmap_sz);
  524. close(fd);
  525. return err;
  526. }
  527. static int do_help(int argc, char **argv)
  528. {
  529. if (json_output) {
  530. jsonw_null(json_wtr);
  531. return 0;
  532. }
  533. fprintf(stderr,
  534. "Usage: %1$s %2$s skeleton FILE\n"
  535. " %1$s %2$s help\n"
  536. "\n"
  537. " " HELP_SPEC_OPTIONS "\n"
  538. "",
  539. bin_name, "gen");
  540. return 0;
  541. }
  542. static const struct cmd cmds[] = {
  543. { "skeleton", do_skeleton },
  544. { "help", do_help },
  545. { 0 }
  546. };
  547. int do_gen(int argc, char **argv)
  548. {
  549. return cmd_select(cmds, argc, argv, do_help);
  550. }