7443879e87afea37122ff4914f10f982a7f3e7df
[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 void 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                 exit(-1);
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                         exit(-1);
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                                 exit(-1);
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         if (n)
261                 exit(-1);
262 }
263
264 static int do_skeleton(int argc, char **argv)
265 {
266         char header_guard[MAX_OBJ_NAME_LEN + sizeof("__SKEL_H__")];
267         size_t i, map_cnt = 0, prog_cnt = 0, file_sz, mmap_sz;
268         DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);
269         char obj_name[MAX_OBJ_NAME_LEN], *obj_data;
270         struct bpf_object *obj = NULL;
271         const char *file, *ident;
272         struct bpf_program *prog;
273         int fd, len, err = -1;
274         struct bpf_map *map;
275         struct btf *btf;
276         struct stat st;
277
278         if (!REQ_ARGS(1)) {
279                 usage();
280                 return -1;
281         }
282         file = GET_ARG();
283
284         if (argc) {
285                 p_err("extra unknown arguments");
286                 return -1;
287         }
288
289         if (stat(file, &st)) {
290                 p_err("failed to stat() %s: %s", file, strerror(errno));
291                 return -1;
292         }
293         file_sz = st.st_size;
294         mmap_sz = roundup(file_sz, sysconf(_SC_PAGE_SIZE));
295         fd = open(file, O_RDONLY);
296         if (fd < 0) {
297                 p_err("failed to open() %s: %s", file, strerror(errno));
298                 return -1;
299         }
300         obj_data = mmap(NULL, mmap_sz, PROT_READ, MAP_PRIVATE, fd, 0);
301         if (obj_data == MAP_FAILED) {
302                 obj_data = NULL;
303                 p_err("failed to mmap() %s: %s", file, strerror(errno));
304                 goto out;
305         }
306         get_obj_name(obj_name, file);
307         opts.object_name = obj_name;
308         obj = bpf_object__open_mem(obj_data, file_sz, &opts);
309         if (IS_ERR(obj)) {
310                 obj = NULL;
311                 p_err("failed to open BPF object file: %ld", PTR_ERR(obj));
312                 goto out;
313         }
314
315         bpf_object__for_each_map(map, obj) {
316                 ident = get_map_ident(map);
317                 if (!ident) {
318                         p_err("ignoring unrecognized internal map '%s'...",
319                               bpf_map__name(map));
320                         continue;
321                 }
322                 map_cnt++;
323         }
324         bpf_object__for_each_program(prog, obj) {
325                 prog_cnt++;
326         }
327
328         get_header_guard(header_guard, obj_name);
329         codegen("\
330                 \n\
331                 /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */   \n\
332                                                                             \n\
333                 /* THIS FILE IS AUTOGENERATED! */                           \n\
334                 #ifndef %2$s                                                \n\
335                 #define %2$s                                                \n\
336                                                                             \n\
337                 #include <stdlib.h>                                         \n\
338                 #include <bpf/libbpf.h>                                     \n\
339                                                                             \n\
340                 struct %1$s {                                               \n\
341                         struct bpf_object_skeleton *skeleton;               \n\
342                         struct bpf_object *obj;                             \n\
343                 ",
344                 obj_name, header_guard
345         );
346
347         if (map_cnt) {
348                 printf("\tstruct {\n");
349                 bpf_object__for_each_map(map, obj) {
350                         ident = get_map_ident(map);
351                         if (!ident)
352                                 continue;
353                         printf("\t\tstruct bpf_map *%s;\n", ident);
354                 }
355                 printf("\t} maps;\n");
356         }
357
358         if (prog_cnt) {
359                 printf("\tstruct {\n");
360                 bpf_object__for_each_program(prog, obj) {
361                         printf("\t\tstruct bpf_program *%s;\n",
362                                bpf_program__name(prog));
363                 }
364                 printf("\t} progs;\n");
365                 printf("\tstruct {\n");
366                 bpf_object__for_each_program(prog, obj) {
367                         printf("\t\tstruct bpf_link *%s;\n",
368                                bpf_program__name(prog));
369                 }
370                 printf("\t} links;\n");
371         }
372
373         btf = bpf_object__btf(obj);
374         if (btf) {
375                 err = codegen_datasecs(obj, obj_name);
376                 if (err)
377                         goto out;
378         }
379
380         codegen("\
381                 \n\
382                 };                                                          \n\
383                                                                             \n\
384                 static void                                                 \n\
385                 %1$s__destroy(struct %1$s *obj)                             \n\
386                 {                                                           \n\
387                         if (!obj)                                           \n\
388                                 return;                                     \n\
389                         if (obj->skeleton)                                  \n\
390                                 bpf_object__destroy_skeleton(obj->skeleton);\n\
391                         free(obj);                                          \n\
392                 }                                                           \n\
393                                                                             \n\
394                 static inline int                                           \n\
395                 %1$s__create_skeleton(struct %1$s *obj);                    \n\
396                                                                             \n\
397                 static inline struct %1$s *                                 \n\
398                 %1$s__open_opts(const struct bpf_object_open_opts *opts)    \n\
399                 {                                                           \n\
400                         struct %1$s *obj;                                   \n\
401                                                                             \n\
402                         obj = (typeof(obj))calloc(1, sizeof(*obj));         \n\
403                         if (!obj)                                           \n\
404                                 return NULL;                                \n\
405                         if (%1$s__create_skeleton(obj))                     \n\
406                                 goto err;                                   \n\
407                         if (bpf_object__open_skeleton(obj->skeleton, opts)) \n\
408                                 goto err;                                   \n\
409                                                                             \n\
410                         return obj;                                         \n\
411                 err:                                                        \n\
412                         %1$s__destroy(obj);                                 \n\
413                         return NULL;                                        \n\
414                 }                                                           \n\
415                                                                             \n\
416                 static inline struct %1$s *                                 \n\
417                 %1$s__open(void)                                            \n\
418                 {                                                           \n\
419                         return %1$s__open_opts(NULL);                       \n\
420                 }                                                           \n\
421                                                                             \n\
422                 static inline int                                           \n\
423                 %1$s__load(struct %1$s *obj)                                \n\
424                 {                                                           \n\
425                         return bpf_object__load_skeleton(obj->skeleton);    \n\
426                 }                                                           \n\
427                                                                             \n\
428                 static inline struct %1$s *                                 \n\
429                 %1$s__open_and_load(void)                                   \n\
430                 {                                                           \n\
431                         struct %1$s *obj;                                   \n\
432                                                                             \n\
433                         obj = %1$s__open();                                 \n\
434                         if (!obj)                                           \n\
435                                 return NULL;                                \n\
436                         if (%1$s__load(obj)) {                              \n\
437                                 %1$s__destroy(obj);                         \n\
438                                 return NULL;                                \n\
439                         }                                                   \n\
440                         return obj;                                         \n\
441                 }                                                           \n\
442                                                                             \n\
443                 static inline int                                           \n\
444                 %1$s__attach(struct %1$s *obj)                              \n\
445                 {                                                           \n\
446                         return bpf_object__attach_skeleton(obj->skeleton);  \n\
447                 }                                                           \n\
448                                                                             \n\
449                 static inline void                                          \n\
450                 %1$s__detach(struct %1$s *obj)                              \n\
451                 {                                                           \n\
452                         return bpf_object__detach_skeleton(obj->skeleton);  \n\
453                 }                                                           \n\
454                 ",
455                 obj_name
456         );
457
458         codegen("\
459                 \n\
460                                                                             \n\
461                 static inline int                                           \n\
462                 %1$s__create_skeleton(struct %1$s *obj)                     \n\
463                 {                                                           \n\
464                         struct bpf_object_skeleton *s;                      \n\
465                                                                             \n\
466                         s = (typeof(s))calloc(1, sizeof(*s));               \n\
467                         if (!s)                                             \n\
468                                 return -1;                                  \n\
469                         obj->skeleton = s;                                  \n\
470                                                                             \n\
471                         s->sz = sizeof(*s);                                 \n\
472                         s->name = \"%1$s\";                                 \n\
473                         s->obj = &obj->obj;                                 \n\
474                 ",
475                 obj_name
476         );
477         if (map_cnt) {
478                 codegen("\
479                         \n\
480                                                                             \n\
481                                 /* maps */                                  \n\
482                                 s->map_cnt = %zu;                           \n\
483                                 s->map_skel_sz = sizeof(*s->maps);          \n\
484                                 s->maps = (typeof(s->maps))calloc(s->map_cnt, s->map_skel_sz);\n\
485                                 if (!s->maps)                               \n\
486                                         goto err;                           \n\
487                         ",
488                         map_cnt
489                 );
490                 i = 0;
491                 bpf_object__for_each_map(map, obj) {
492                         ident = get_map_ident(map);
493
494                         if (!ident)
495                                 continue;
496
497                         codegen("\
498                                 \n\
499                                                                             \n\
500                                         s->maps[%zu].name = \"%s\";         \n\
501                                         s->maps[%zu].map = &obj->maps.%s;   \n\
502                                 ",
503                                 i, bpf_map__name(map), i, ident);
504                         /* memory-mapped internal maps */
505                         if (bpf_map__is_internal(map) &&
506                             (bpf_map__def(map)->map_flags & BPF_F_MMAPABLE)) {
507                                 printf("\ts->maps[%zu].mmaped = (void **)&obj->%s;\n",
508                                        i, ident);
509                         }
510                         i++;
511                 }
512         }
513         if (prog_cnt) {
514                 codegen("\
515                         \n\
516                                                                             \n\
517                                 /* programs */                              \n\
518                                 s->prog_cnt = %zu;                          \n\
519                                 s->prog_skel_sz = sizeof(*s->progs);        \n\
520                                 s->progs = (typeof(s->progs))calloc(s->prog_cnt, s->prog_skel_sz);\n\
521                                 if (!s->progs)                              \n\
522                                         goto err;                           \n\
523                         ",
524                         prog_cnt
525                 );
526                 i = 0;
527                 bpf_object__for_each_program(prog, obj) {
528                         codegen("\
529                                 \n\
530                                                                             \n\
531                                         s->progs[%1$zu].name = \"%2$s\";    \n\
532                                         s->progs[%1$zu].prog = &obj->progs.%2$s;\n\
533                                         s->progs[%1$zu].link = &obj->links.%2$s;\n\
534                                 ",
535                                 i, bpf_program__name(prog));
536                         i++;
537                 }
538         }
539         codegen("\
540                 \n\
541                                                                             \n\
542                         s->data_sz = %d;                                    \n\
543                         s->data = (void *)\"\\                              \n\
544                 ",
545                 file_sz);
546
547         /* embed contents of BPF object file */
548         for (i = 0, len = 0; i < file_sz; i++) {
549                 int w = obj_data[i] ? 4 : 2;
550
551                 len += w;
552                 if (len > 78) {
553                         printf("\\\n");
554                         len = w;
555                 }
556                 if (!obj_data[i])
557                         printf("\\0");
558                 else
559                         printf("\\x%02x", (unsigned char)obj_data[i]);
560         }
561
562         codegen("\
563                 \n\
564                 \";                                                         \n\
565                                                                             \n\
566                         return 0;                                           \n\
567                 err:                                                        \n\
568                         bpf_object__destroy_skeleton(s);                    \n\
569                         return -1;                                          \n\
570                 }                                                           \n\
571                                                                             \n\
572                 #endif /* %s */                                             \n\
573                 ",
574                 header_guard);
575         err = 0;
576 out:
577         bpf_object__close(obj);
578         if (obj_data)
579                 munmap(obj_data, mmap_sz);
580         close(fd);
581         return err;
582 }
583
584 static int do_help(int argc, char **argv)
585 {
586         if (json_output) {
587                 jsonw_null(json_wtr);
588                 return 0;
589         }
590
591         fprintf(stderr,
592                 "Usage: %1$s %2$s skeleton FILE\n"
593                 "       %1$s %2$s help\n"
594                 "\n"
595                 "       " HELP_SPEC_OPTIONS "\n"
596                 "",
597                 bin_name, "gen");
598
599         return 0;
600 }
601
602 static const struct cmd cmds[] = {
603         { "skeleton",   do_skeleton },
604         { "help",       do_help },
605         { 0 }
606 };
607
608 int do_gen(int argc, char **argv)
609 {
610         return cmd_select(cmds, argc, argv, do_help);
611 }