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