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