linux/tools/bpf/bpftool/gen.c
<<
>>
Prefs
   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#include <bpf/bpf_gen_internal.h>
  22
  23#include "json_writer.h"
  24#include "main.h"
  25
  26#define MAX_OBJ_NAME_LEN 64
  27
  28static void sanitize_identifier(char *name)
  29{
  30        int i;
  31
  32        for (i = 0; name[i]; i++)
  33                if (!isalnum(name[i]) && name[i] != '_')
  34                        name[i] = '_';
  35}
  36
  37static bool str_has_suffix(const char *str, const char *suffix)
  38{
  39        size_t i, n1 = strlen(str), n2 = strlen(suffix);
  40
  41        if (n1 < n2)
  42                return false;
  43
  44        for (i = 0; i < n2; i++) {
  45                if (str[n1 - i - 1] != suffix[n2 - i - 1])
  46                        return false;
  47        }
  48
  49        return true;
  50}
  51
  52static void get_obj_name(char *name, const char *file)
  53{
  54        /* Using basename() GNU version which doesn't modify arg. */
  55        strncpy(name, basename(file), MAX_OBJ_NAME_LEN - 1);
  56        name[MAX_OBJ_NAME_LEN - 1] = '\0';
  57        if (str_has_suffix(name, ".o"))
  58                name[strlen(name) - 2] = '\0';
  59        sanitize_identifier(name);
  60}
  61
  62static void get_header_guard(char *guard, const char *obj_name)
  63{
  64        int i;
  65
  66        sprintf(guard, "__%s_SKEL_H__", obj_name);
  67        for (i = 0; guard[i]; i++)
  68                guard[i] = toupper(guard[i]);
  69}
  70
  71static const char *get_map_ident(const struct bpf_map *map)
  72{
  73        const char *name = bpf_map__name(map);
  74
  75        if (!bpf_map__is_internal(map))
  76                return name;
  77
  78        if (str_has_suffix(name, ".data"))
  79                return "data";
  80        else if (str_has_suffix(name, ".rodata"))
  81                return "rodata";
  82        else if (str_has_suffix(name, ".bss"))
  83                return "bss";
  84        else if (str_has_suffix(name, ".kconfig"))
  85                return "kconfig";
  86        else
  87                return NULL;
  88}
  89
  90static void codegen_btf_dump_printf(void *ctx, const char *fmt, va_list args)
  91{
  92        vprintf(fmt, args);
  93}
  94
  95static int codegen_datasec_def(struct bpf_object *obj,
  96                               struct btf *btf,
  97                               struct btf_dump *d,
  98                               const struct btf_type *sec,
  99                               const char *obj_name)
 100{
 101        const char *sec_name = btf__name_by_offset(btf, sec->name_off);
 102        const struct btf_var_secinfo *sec_var = btf_var_secinfos(sec);
 103        int i, err, off = 0, pad_cnt = 0, vlen = btf_vlen(sec);
 104        const char *sec_ident;
 105        char var_ident[256];
 106        bool strip_mods = false;
 107
 108        if (strcmp(sec_name, ".data") == 0) {
 109                sec_ident = "data";
 110                strip_mods = true;
 111        } else if (strcmp(sec_name, ".bss") == 0) {
 112                sec_ident = "bss";
 113                strip_mods = true;
 114        } else if (strcmp(sec_name, ".rodata") == 0) {
 115                sec_ident = "rodata";
 116                strip_mods = true;
 117        } else if (strcmp(sec_name, ".kconfig") == 0) {
 118                sec_ident = "kconfig";
 119        } else {
 120                return 0;
 121        }
 122
 123        printf("        struct %s__%s {\n", obj_name, sec_ident);
 124        for (i = 0; i < vlen; i++, sec_var++) {
 125                const struct btf_type *var = btf__type_by_id(btf, sec_var->type);
 126                const char *var_name = btf__name_by_offset(btf, var->name_off);
 127                DECLARE_LIBBPF_OPTS(btf_dump_emit_type_decl_opts, opts,
 128                        .field_name = var_ident,
 129                        .indent_level = 2,
 130                        .strip_mods = strip_mods,
 131                );
 132                int need_off = sec_var->offset, align_off, align;
 133                __u32 var_type_id = var->type;
 134
 135                /* static variables are not exposed through BPF skeleton */
 136                if (btf_var(var)->linkage == BTF_VAR_STATIC)
 137                        continue;
 138
 139                if (off > need_off) {
 140                        p_err("Something is wrong for %s's variable #%d: need offset %d, already at %d.\n",
 141                              sec_name, i, need_off, off);
 142                        return -EINVAL;
 143                }
 144
 145                align = btf__align_of(btf, var->type);
 146                if (align <= 0) {
 147                        p_err("Failed to determine alignment of variable '%s': %d",
 148                              var_name, align);
 149                        return -EINVAL;
 150                }
 151                /* Assume 32-bit architectures when generating data section
 152                 * struct memory layout. Given bpftool can't know which target
 153                 * host architecture it's emitting skeleton for, we need to be
 154                 * conservative and assume 32-bit one to ensure enough padding
 155                 * bytes are generated for pointer and long types. This will
 156                 * still work correctly for 64-bit architectures, because in
 157                 * the worst case we'll generate unnecessary padding field,
 158                 * which on 64-bit architectures is not strictly necessary and
 159                 * would be handled by natural 8-byte alignment. But it still
 160                 * will be a correct memory layout, based on recorded offsets
 161                 * in BTF.
 162                 */
 163                if (align > 4)
 164                        align = 4;
 165
 166                align_off = (off + align - 1) / align * align;
 167                if (align_off != need_off) {
 168                        printf("\t\tchar __pad%d[%d];\n",
 169                               pad_cnt, need_off - off);
 170                        pad_cnt++;
 171                }
 172
 173                /* sanitize variable name, e.g., for static vars inside
 174                 * a function, it's name is '<function name>.<variable name>',
 175                 * which we'll turn into a '<function name>_<variable name>'
 176                 */
 177                var_ident[0] = '\0';
 178                strncat(var_ident, var_name, sizeof(var_ident) - 1);
 179                sanitize_identifier(var_ident);
 180
 181                printf("\t\t");
 182                err = btf_dump__emit_type_decl(d, var_type_id, &opts);
 183                if (err)
 184                        return err;
 185                printf(";\n");
 186
 187                off = sec_var->offset + sec_var->size;
 188        }
 189        printf("        } *%s;\n", sec_ident);
 190        return 0;
 191}
 192
 193static int codegen_datasecs(struct bpf_object *obj, const char *obj_name)
 194{
 195        struct btf *btf = bpf_object__btf(obj);
 196        int n = btf__get_nr_types(btf);
 197        struct btf_dump *d;
 198        int i, err = 0;
 199
 200        d = btf_dump__new(btf, NULL, NULL, codegen_btf_dump_printf);
 201        if (IS_ERR(d))
 202                return PTR_ERR(d);
 203
 204        for (i = 1; i <= n; i++) {
 205                const struct btf_type *t = btf__type_by_id(btf, i);
 206
 207                if (!btf_is_datasec(t))
 208                        continue;
 209
 210                err = codegen_datasec_def(obj, btf, d, t, obj_name);
 211                if (err)
 212                        goto out;
 213        }
 214out:
 215        btf_dump__free(d);
 216        return err;
 217}
 218
 219static void codegen(const char *template, ...)
 220{
 221        const char *src, *end;
 222        int skip_tabs = 0, n;
 223        char *s, *dst;
 224        va_list args;
 225        char c;
 226
 227        n = strlen(template);
 228        s = malloc(n + 1);
 229        if (!s)
 230                exit(-1);
 231        src = template;
 232        dst = s;
 233
 234        /* find out "baseline" indentation to skip */
 235        while ((c = *src++)) {
 236                if (c == '\t') {
 237                        skip_tabs++;
 238                } else if (c == '\n') {
 239                        break;
 240                } else {
 241                        p_err("unrecognized character at pos %td in template '%s'",
 242                              src - template - 1, template);
 243                        free(s);
 244                        exit(-1);
 245                }
 246        }
 247
 248        while (*src) {
 249                /* skip baseline indentation tabs */
 250                for (n = skip_tabs; n > 0; n--, src++) {
 251                        if (*src != '\t') {
 252                                p_err("not enough tabs at pos %td in template '%s'",
 253                                      src - template - 1, template);
 254                                free(s);
 255                                exit(-1);
 256                        }
 257                }
 258                /* trim trailing whitespace */
 259                end = strchrnul(src, '\n');
 260                for (n = end - src; n > 0 && isspace(src[n - 1]); n--)
 261                        ;
 262                memcpy(dst, src, n);
 263                dst += n;
 264                if (*end)
 265                        *dst++ = '\n';
 266                src = *end ? end + 1 : end;
 267        }
 268        *dst++ = '\0';
 269
 270        /* print out using adjusted template */
 271        va_start(args, template);
 272        n = vprintf(s, args);
 273        va_end(args);
 274
 275        free(s);
 276}
 277
 278static void print_hex(const char *data, int data_sz)
 279{
 280        int i, len;
 281
 282        for (i = 0, len = 0; i < data_sz; i++) {
 283                int w = data[i] ? 4 : 2;
 284
 285                len += w;
 286                if (len > 78) {
 287                        printf("\\\n");
 288                        len = w;
 289                }
 290                if (!data[i])
 291                        printf("\\0");
 292                else
 293                        printf("\\x%02x", (unsigned char)data[i]);
 294        }
 295}
 296
 297static size_t bpf_map_mmap_sz(const struct bpf_map *map)
 298{
 299        long page_sz = sysconf(_SC_PAGE_SIZE);
 300        size_t map_sz;
 301
 302        map_sz = (size_t)roundup(bpf_map__value_size(map), 8) * bpf_map__max_entries(map);
 303        map_sz = roundup(map_sz, page_sz);
 304        return map_sz;
 305}
 306
 307static void codegen_attach_detach(struct bpf_object *obj, const char *obj_name)
 308{
 309        struct bpf_program *prog;
 310
 311        bpf_object__for_each_program(prog, obj) {
 312                const char *tp_name;
 313
 314                codegen("\
 315                        \n\
 316                        \n\
 317                        static inline int                                           \n\
 318                        %1$s__%2$s__attach(struct %1$s *skel)                       \n\
 319                        {                                                           \n\
 320                                int prog_fd = skel->progs.%2$s.prog_fd;             \n\
 321                        ", obj_name, bpf_program__name(prog));
 322
 323                switch (bpf_program__get_type(prog)) {
 324                case BPF_PROG_TYPE_RAW_TRACEPOINT:
 325                        tp_name = strchr(bpf_program__section_name(prog), '/') + 1;
 326                        printf("\tint fd = bpf_raw_tracepoint_open(\"%s\", prog_fd);\n", tp_name);
 327                        break;
 328                case BPF_PROG_TYPE_TRACING:
 329                        printf("\tint fd = bpf_raw_tracepoint_open(NULL, prog_fd);\n");
 330                        break;
 331                default:
 332                        printf("\tint fd = ((void)prog_fd, 0); /* auto-attach not supported */\n");
 333                        break;
 334                }
 335                codegen("\
 336                        \n\
 337                                                                                    \n\
 338                                if (fd > 0)                                         \n\
 339                                        skel->links.%1$s_fd = fd;                   \n\
 340                                return fd;                                          \n\
 341                        }                                                           \n\
 342                        ", bpf_program__name(prog));
 343        }
 344
 345        codegen("\
 346                \n\
 347                                                                            \n\
 348                static inline int                                           \n\
 349                %1$s__attach(struct %1$s *skel)                             \n\
 350                {                                                           \n\
 351                        int ret = 0;                                        \n\
 352                                                                            \n\
 353                ", obj_name);
 354
 355        bpf_object__for_each_program(prog, obj) {
 356                codegen("\
 357                        \n\
 358                                ret = ret < 0 ? ret : %1$s__%2$s__attach(skel);   \n\
 359                        ", obj_name, bpf_program__name(prog));
 360        }
 361
 362        codegen("\
 363                \n\
 364                        return ret < 0 ? ret : 0;                           \n\
 365                }                                                           \n\
 366                                                                            \n\
 367                static inline void                                          \n\
 368                %1$s__detach(struct %1$s *skel)                             \n\
 369                {                                                           \n\
 370                ", obj_name);
 371
 372        bpf_object__for_each_program(prog, obj) {
 373                codegen("\
 374                        \n\
 375                                skel_closenz(skel->links.%1$s_fd);          \n\
 376                        ", bpf_program__name(prog));
 377        }
 378
 379        codegen("\
 380                \n\
 381                }                                                           \n\
 382                ");
 383}
 384
 385static void codegen_destroy(struct bpf_object *obj, const char *obj_name)
 386{
 387        struct bpf_program *prog;
 388        struct bpf_map *map;
 389
 390        codegen("\
 391                \n\
 392                static void                                                 \n\
 393                %1$s__destroy(struct %1$s *skel)                            \n\
 394                {                                                           \n\
 395                        if (!skel)                                          \n\
 396                                return;                                     \n\
 397                        %1$s__detach(skel);                                 \n\
 398                ",
 399                obj_name);
 400
 401        bpf_object__for_each_program(prog, obj) {
 402                codegen("\
 403                        \n\
 404                                skel_closenz(skel->progs.%1$s.prog_fd);     \n\
 405                        ", bpf_program__name(prog));
 406        }
 407
 408        bpf_object__for_each_map(map, obj) {
 409                const char * ident;
 410
 411                ident = get_map_ident(map);
 412                if (!ident)
 413                        continue;
 414                if (bpf_map__is_internal(map) &&
 415                    (bpf_map__def(map)->map_flags & BPF_F_MMAPABLE))
 416                        printf("\tmunmap(skel->%1$s, %2$zd);\n",
 417                               ident, bpf_map_mmap_sz(map));
 418                codegen("\
 419                        \n\
 420                                skel_closenz(skel->maps.%1$s.map_fd);       \n\
 421                        ", ident);
 422        }
 423        codegen("\
 424                \n\
 425                        free(skel);                                         \n\
 426                }                                                           \n\
 427                ",
 428                obj_name);
 429}
 430
 431static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *header_guard)
 432{
 433        struct bpf_object_load_attr load_attr = {};
 434        DECLARE_LIBBPF_OPTS(gen_loader_opts, opts);
 435        struct bpf_map *map;
 436        int err = 0;
 437
 438        err = bpf_object__gen_loader(obj, &opts);
 439        if (err)
 440                return err;
 441
 442        load_attr.obj = obj;
 443        if (verifier_logs)
 444                /* log_level1 + log_level2 + stats, but not stable UAPI */
 445                load_attr.log_level = 1 + 2 + 4;
 446
 447        err = bpf_object__load_xattr(&load_attr);
 448        if (err) {
 449                p_err("failed to load object file");
 450                goto out;
 451        }
 452        /* If there was no error during load then gen_loader_opts
 453         * are populated with the loader program.
 454         */
 455
 456        /* finish generating 'struct skel' */
 457        codegen("\
 458                \n\
 459                };                                                          \n\
 460                ", obj_name);
 461
 462
 463        codegen_attach_detach(obj, obj_name);
 464
 465        codegen_destroy(obj, obj_name);
 466
 467        codegen("\
 468                \n\
 469                static inline struct %1$s *                                 \n\
 470                %1$s__open(void)                                            \n\
 471                {                                                           \n\
 472                        struct %1$s *skel;                                  \n\
 473                                                                            \n\
 474                        skel = calloc(sizeof(*skel), 1);                    \n\
 475                        if (!skel)                                          \n\
 476                                goto cleanup;                               \n\
 477                        skel->ctx.sz = (void *)&skel->links - (void *)skel; \n\
 478                ",
 479                obj_name, opts.data_sz);
 480        bpf_object__for_each_map(map, obj) {
 481                const char *ident;
 482                const void *mmap_data = NULL;
 483                size_t mmap_size = 0;
 484
 485                ident = get_map_ident(map);
 486                if (!ident)
 487                        continue;
 488
 489                if (!bpf_map__is_internal(map) ||
 490                    !(bpf_map__def(map)->map_flags & BPF_F_MMAPABLE))
 491                        continue;
 492
 493                codegen("\
 494                        \n\
 495                                skel->%1$s =                                     \n\
 496                                        mmap(NULL, %2$zd, PROT_READ | PROT_WRITE,\n\
 497                                             MAP_SHARED | MAP_ANONYMOUS, -1, 0); \n\
 498                                if (skel->%1$s == (void *) -1)                   \n\
 499                                        goto cleanup;                            \n\
 500                                memcpy(skel->%1$s, (void *)\"\\                  \n\
 501                        ", ident, bpf_map_mmap_sz(map));
 502                mmap_data = bpf_map__initial_value(map, &mmap_size);
 503                print_hex(mmap_data, mmap_size);
 504                printf("\", %2$zd);\n"
 505                       "\tskel->maps.%1$s.initial_value = (__u64)(long)skel->%1$s;\n",
 506                       ident, mmap_size);
 507        }
 508        codegen("\
 509                \n\
 510                        return skel;                                        \n\
 511                cleanup:                                                    \n\
 512                        %1$s__destroy(skel);                                \n\
 513                        return NULL;                                        \n\
 514                }                                                           \n\
 515                                                                            \n\
 516                static inline int                                           \n\
 517                %1$s__load(struct %1$s *skel)                               \n\
 518                {                                                           \n\
 519                        struct bpf_load_and_run_opts opts = {};             \n\
 520                        int err;                                            \n\
 521                                                                            \n\
 522                        opts.ctx = (struct bpf_loader_ctx *)skel;           \n\
 523                        opts.data_sz = %2$d;                                \n\
 524                        opts.data = (void *)\"\\                            \n\
 525                ",
 526                obj_name, opts.data_sz);
 527        print_hex(opts.data, opts.data_sz);
 528        codegen("\
 529                \n\
 530                \";                                                         \n\
 531                ");
 532
 533        codegen("\
 534                \n\
 535                        opts.insns_sz = %d;                                 \n\
 536                        opts.insns = (void *)\"\\                           \n\
 537                ",
 538                opts.insns_sz);
 539        print_hex(opts.insns, opts.insns_sz);
 540        codegen("\
 541                \n\
 542                \";                                                         \n\
 543                        err = bpf_load_and_run(&opts);                      \n\
 544                        if (err < 0)                                        \n\
 545                                return err;                                 \n\
 546                ", obj_name);
 547        bpf_object__for_each_map(map, obj) {
 548                const char *ident, *mmap_flags;
 549
 550                ident = get_map_ident(map);
 551                if (!ident)
 552                        continue;
 553
 554                if (!bpf_map__is_internal(map) ||
 555                    !(bpf_map__def(map)->map_flags & BPF_F_MMAPABLE))
 556                        continue;
 557                if (bpf_map__def(map)->map_flags & BPF_F_RDONLY_PROG)
 558                        mmap_flags = "PROT_READ";
 559                else
 560                        mmap_flags = "PROT_READ | PROT_WRITE";
 561
 562                printf("\tskel->%1$s =\n"
 563                       "\t\tmmap(skel->%1$s, %2$zd, %3$s, MAP_SHARED | MAP_FIXED,\n"
 564                       "\t\t\tskel->maps.%1$s.map_fd, 0);\n",
 565                       ident, bpf_map_mmap_sz(map), mmap_flags);
 566        }
 567        codegen("\
 568                \n\
 569                        return 0;                                           \n\
 570                }                                                           \n\
 571                                                                            \n\
 572                static inline struct %1$s *                                 \n\
 573                %1$s__open_and_load(void)                                   \n\
 574                {                                                           \n\
 575                        struct %1$s *skel;                                  \n\
 576                                                                            \n\
 577                        skel = %1$s__open();                                \n\
 578                        if (!skel)                                          \n\
 579                                return NULL;                                \n\
 580                        if (%1$s__load(skel)) {                             \n\
 581                                %1$s__destroy(skel);                        \n\
 582                                return NULL;                                \n\
 583                        }                                                   \n\
 584                        return skel;                                        \n\
 585                }                                                           \n\
 586                ", obj_name);
 587
 588        codegen("\
 589                \n\
 590                                                                            \n\
 591                #endif /* %s */                                             \n\
 592                ",
 593                header_guard);
 594        err = 0;
 595out:
 596        return err;
 597}
 598
 599static int do_skeleton(int argc, char **argv)
 600{
 601        char header_guard[MAX_OBJ_NAME_LEN + sizeof("__SKEL_H__")];
 602        size_t i, map_cnt = 0, prog_cnt = 0, file_sz, mmap_sz;
 603        DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);
 604        char obj_name[MAX_OBJ_NAME_LEN] = "", *obj_data;
 605        struct bpf_object *obj = NULL;
 606        const char *file, *ident;
 607        struct bpf_program *prog;
 608        int fd, err = -1;
 609        struct bpf_map *map;
 610        struct btf *btf;
 611        struct stat st;
 612
 613        if (!REQ_ARGS(1)) {
 614                usage();
 615                return -1;
 616        }
 617        file = GET_ARG();
 618
 619        while (argc) {
 620                if (!REQ_ARGS(2))
 621                        return -1;
 622
 623                if (is_prefix(*argv, "name")) {
 624                        NEXT_ARG();
 625
 626                        if (obj_name[0] != '\0') {
 627                                p_err("object name already specified");
 628                                return -1;
 629                        }
 630
 631                        strncpy(obj_name, *argv, MAX_OBJ_NAME_LEN - 1);
 632                        obj_name[MAX_OBJ_NAME_LEN - 1] = '\0';
 633                } else {
 634                        p_err("unknown arg %s", *argv);
 635                        return -1;
 636                }
 637
 638                NEXT_ARG();
 639        }
 640
 641        if (argc) {
 642                p_err("extra unknown arguments");
 643                return -1;
 644        }
 645
 646        if (stat(file, &st)) {
 647                p_err("failed to stat() %s: %s", file, strerror(errno));
 648                return -1;
 649        }
 650        file_sz = st.st_size;
 651        mmap_sz = roundup(file_sz, sysconf(_SC_PAGE_SIZE));
 652        fd = open(file, O_RDONLY);
 653        if (fd < 0) {
 654                p_err("failed to open() %s: %s", file, strerror(errno));
 655                return -1;
 656        }
 657        obj_data = mmap(NULL, mmap_sz, PROT_READ, MAP_PRIVATE, fd, 0);
 658        if (obj_data == MAP_FAILED) {
 659                obj_data = NULL;
 660                p_err("failed to mmap() %s: %s", file, strerror(errno));
 661                goto out;
 662        }
 663        if (obj_name[0] == '\0')
 664                get_obj_name(obj_name, file);
 665        opts.object_name = obj_name;
 666        obj = bpf_object__open_mem(obj_data, file_sz, &opts);
 667        if (IS_ERR(obj)) {
 668                char err_buf[256];
 669
 670                libbpf_strerror(PTR_ERR(obj), err_buf, sizeof(err_buf));
 671                p_err("failed to open BPF object file: %s", err_buf);
 672                obj = NULL;
 673                goto out;
 674        }
 675
 676        bpf_object__for_each_map(map, obj) {
 677                ident = get_map_ident(map);
 678                if (!ident) {
 679                        p_err("ignoring unrecognized internal map '%s'...",
 680                              bpf_map__name(map));
 681                        continue;
 682                }
 683                map_cnt++;
 684        }
 685        bpf_object__for_each_program(prog, obj) {
 686                prog_cnt++;
 687        }
 688
 689        get_header_guard(header_guard, obj_name);
 690        if (use_loader) {
 691                codegen("\
 692                \n\
 693                /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */   \n\
 694                /* THIS FILE IS AUTOGENERATED! */                           \n\
 695                #ifndef %2$s                                                \n\
 696                #define %2$s                                                \n\
 697                                                                            \n\
 698                #include <stdlib.h>                                         \n\
 699                #include <bpf/bpf.h>                                        \n\
 700                #include <bpf/skel_internal.h>                              \n\
 701                                                                            \n\
 702                struct %1$s {                                               \n\
 703                        struct bpf_loader_ctx ctx;                          \n\
 704                ",
 705                obj_name, header_guard
 706                );
 707        } else {
 708                codegen("\
 709                \n\
 710                /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */   \n\
 711                                                                            \n\
 712                /* THIS FILE IS AUTOGENERATED! */                           \n\
 713                #ifndef %2$s                                                \n\
 714                #define %2$s                                                \n\
 715                                                                            \n\
 716                #include <errno.h>                                          \n\
 717                #include <stdlib.h>                                         \n\
 718                #include <bpf/libbpf.h>                                     \n\
 719                                                                            \n\
 720                struct %1$s {                                               \n\
 721                        struct bpf_object_skeleton *skeleton;               \n\
 722                        struct bpf_object *obj;                             \n\
 723                ",
 724                obj_name, header_guard
 725                );
 726        }
 727
 728        if (map_cnt) {
 729                printf("\tstruct {\n");
 730                bpf_object__for_each_map(map, obj) {
 731                        ident = get_map_ident(map);
 732                        if (!ident)
 733                                continue;
 734                        if (use_loader)
 735                                printf("\t\tstruct bpf_map_desc %s;\n", ident);
 736                        else
 737                                printf("\t\tstruct bpf_map *%s;\n", ident);
 738                }
 739                printf("\t} maps;\n");
 740        }
 741
 742        if (prog_cnt) {
 743                printf("\tstruct {\n");
 744                bpf_object__for_each_program(prog, obj) {
 745                        if (use_loader)
 746                                printf("\t\tstruct bpf_prog_desc %s;\n",
 747                                       bpf_program__name(prog));
 748                        else
 749                                printf("\t\tstruct bpf_program *%s;\n",
 750                                       bpf_program__name(prog));
 751                }
 752                printf("\t} progs;\n");
 753                printf("\tstruct {\n");
 754                bpf_object__for_each_program(prog, obj) {
 755                        if (use_loader)
 756                                printf("\t\tint %s_fd;\n",
 757                                       bpf_program__name(prog));
 758                        else
 759                                printf("\t\tstruct bpf_link *%s;\n",
 760                                       bpf_program__name(prog));
 761                }
 762                printf("\t} links;\n");
 763        }
 764
 765        btf = bpf_object__btf(obj);
 766        if (btf) {
 767                err = codegen_datasecs(obj, obj_name);
 768                if (err)
 769                        goto out;
 770        }
 771        if (use_loader) {
 772                err = gen_trace(obj, obj_name, header_guard);
 773                goto out;
 774        }
 775
 776        codegen("\
 777                \n\
 778                };                                                          \n\
 779                                                                            \n\
 780                static void                                                 \n\
 781                %1$s__destroy(struct %1$s *obj)                             \n\
 782                {                                                           \n\
 783                        if (!obj)                                           \n\
 784                                return;                                     \n\
 785                        if (obj->skeleton)                                  \n\
 786                                bpf_object__destroy_skeleton(obj->skeleton);\n\
 787                        free(obj);                                          \n\
 788                }                                                           \n\
 789                                                                            \n\
 790                static inline int                                           \n\
 791                %1$s__create_skeleton(struct %1$s *obj);                    \n\
 792                                                                            \n\
 793                static inline struct %1$s *                                 \n\
 794                %1$s__open_opts(const struct bpf_object_open_opts *opts)    \n\
 795                {                                                           \n\
 796                        struct %1$s *obj;                                   \n\
 797                        int err;                                            \n\
 798                                                                            \n\
 799                        obj = (struct %1$s *)calloc(1, sizeof(*obj));       \n\
 800                        if (!obj) {                                         \n\
 801                                errno = ENOMEM;                             \n\
 802                                return NULL;                                \n\
 803                        }                                                   \n\
 804                                                                            \n\
 805                        err = %1$s__create_skeleton(obj);                   \n\
 806                        err = err ?: bpf_object__open_skeleton(obj->skeleton, opts);\n\
 807                        if (err)                                            \n\
 808                                goto err_out;                               \n\
 809                                                                            \n\
 810                        return obj;                                         \n\
 811                err_out:                                                    \n\
 812                        %1$s__destroy(obj);                                 \n\
 813                        errno = -err;                                       \n\
 814                        return NULL;                                        \n\
 815                }                                                           \n\
 816                                                                            \n\
 817                static inline struct %1$s *                                 \n\
 818                %1$s__open(void)                                            \n\
 819                {                                                           \n\
 820                        return %1$s__open_opts(NULL);                       \n\
 821                }                                                           \n\
 822                                                                            \n\
 823                static inline int                                           \n\
 824                %1$s__load(struct %1$s *obj)                                \n\
 825                {                                                           \n\
 826                        return bpf_object__load_skeleton(obj->skeleton);    \n\
 827                }                                                           \n\
 828                                                                            \n\
 829                static inline struct %1$s *                                 \n\
 830                %1$s__open_and_load(void)                                   \n\
 831                {                                                           \n\
 832                        struct %1$s *obj;                                   \n\
 833                        int err;                                            \n\
 834                                                                            \n\
 835                        obj = %1$s__open();                                 \n\
 836                        if (!obj)                                           \n\
 837                                return NULL;                                \n\
 838                        err = %1$s__load(obj);                              \n\
 839                        if (err) {                                          \n\
 840                                %1$s__destroy(obj);                         \n\
 841                                errno = -err;                               \n\
 842                                return NULL;                                \n\
 843                        }                                                   \n\
 844                        return obj;                                         \n\
 845                }                                                           \n\
 846                                                                            \n\
 847                static inline int                                           \n\
 848                %1$s__attach(struct %1$s *obj)                              \n\
 849                {                                                           \n\
 850                        return bpf_object__attach_skeleton(obj->skeleton);  \n\
 851                }                                                           \n\
 852                                                                            \n\
 853                static inline void                                          \n\
 854                %1$s__detach(struct %1$s *obj)                              \n\
 855                {                                                           \n\
 856                        return bpf_object__detach_skeleton(obj->skeleton);  \n\
 857                }                                                           \n\
 858                ",
 859                obj_name
 860        );
 861
 862        codegen("\
 863                \n\
 864                                                                            \n\
 865                static inline int                                           \n\
 866                %1$s__create_skeleton(struct %1$s *obj)                     \n\
 867                {                                                           \n\
 868                        struct bpf_object_skeleton *s;                      \n\
 869                                                                            \n\
 870                        s = (struct bpf_object_skeleton *)calloc(1, sizeof(*s));\n\
 871                        if (!s)                                             \n\
 872                                goto err;                                   \n\
 873                        obj->skeleton = s;                                  \n\
 874                                                                            \n\
 875                        s->sz = sizeof(*s);                                 \n\
 876                        s->name = \"%1$s\";                                 \n\
 877                        s->obj = &obj->obj;                                 \n\
 878                ",
 879                obj_name
 880        );
 881        if (map_cnt) {
 882                codegen("\
 883                        \n\
 884                                                                            \n\
 885                                /* maps */                                  \n\
 886                                s->map_cnt = %zu;                           \n\
 887                                s->map_skel_sz = sizeof(*s->maps);          \n\
 888                                s->maps = (struct bpf_map_skeleton *)calloc(s->map_cnt, s->map_skel_sz);\n\
 889                                if (!s->maps)                               \n\
 890                                        goto err;                           \n\
 891                        ",
 892                        map_cnt
 893                );
 894                i = 0;
 895                bpf_object__for_each_map(map, obj) {
 896                        ident = get_map_ident(map);
 897
 898                        if (!ident)
 899                                continue;
 900
 901                        codegen("\
 902                                \n\
 903                                                                            \n\
 904                                        s->maps[%zu].name = \"%s\";         \n\
 905                                        s->maps[%zu].map = &obj->maps.%s;   \n\
 906                                ",
 907                                i, bpf_map__name(map), i, ident);
 908                        /* memory-mapped internal maps */
 909                        if (bpf_map__is_internal(map) &&
 910                            (bpf_map__def(map)->map_flags & BPF_F_MMAPABLE)) {
 911                                printf("\ts->maps[%zu].mmaped = (void **)&obj->%s;\n",
 912                                       i, ident);
 913                        }
 914                        i++;
 915                }
 916        }
 917        if (prog_cnt) {
 918                codegen("\
 919                        \n\
 920                                                                            \n\
 921                                /* programs */                              \n\
 922                                s->prog_cnt = %zu;                          \n\
 923                                s->prog_skel_sz = sizeof(*s->progs);        \n\
 924                                s->progs = (struct bpf_prog_skeleton *)calloc(s->prog_cnt, s->prog_skel_sz);\n\
 925                                if (!s->progs)                              \n\
 926                                        goto err;                           \n\
 927                        ",
 928                        prog_cnt
 929                );
 930                i = 0;
 931                bpf_object__for_each_program(prog, obj) {
 932                        codegen("\
 933                                \n\
 934                                                                            \n\
 935                                        s->progs[%1$zu].name = \"%2$s\";    \n\
 936                                        s->progs[%1$zu].prog = &obj->progs.%2$s;\n\
 937                                        s->progs[%1$zu].link = &obj->links.%2$s;\n\
 938                                ",
 939                                i, bpf_program__name(prog));
 940                        i++;
 941                }
 942        }
 943        codegen("\
 944                \n\
 945                                                                            \n\
 946                        s->data_sz = %d;                                    \n\
 947                        s->data = (void *)\"\\                              \n\
 948                ",
 949                file_sz);
 950
 951        /* embed contents of BPF object file */
 952        print_hex(obj_data, file_sz);
 953
 954        codegen("\
 955                \n\
 956                \";                                                         \n\
 957                                                                            \n\
 958                        return 0;                                           \n\
 959                err:                                                        \n\
 960                        bpf_object__destroy_skeleton(s);                    \n\
 961                        return -ENOMEM;                                     \n\
 962                }                                                           \n\
 963                                                                            \n\
 964                #endif /* %s */                                             \n\
 965                ",
 966                header_guard);
 967        err = 0;
 968out:
 969        bpf_object__close(obj);
 970        if (obj_data)
 971                munmap(obj_data, mmap_sz);
 972        close(fd);
 973        return err;
 974}
 975
 976static int do_object(int argc, char **argv)
 977{
 978        struct bpf_linker *linker;
 979        const char *output_file, *file;
 980        int err = 0;
 981
 982        if (!REQ_ARGS(2)) {
 983                usage();
 984                return -1;
 985        }
 986
 987        output_file = GET_ARG();
 988
 989        linker = bpf_linker__new(output_file, NULL);
 990        if (!linker) {
 991                p_err("failed to create BPF linker instance");
 992                return -1;
 993        }
 994
 995        while (argc) {
 996                file = GET_ARG();
 997
 998                err = bpf_linker__add_file(linker, file, NULL);
 999                if (err) {
1000                        p_err("failed to link '%s': %s (%d)", file, strerror(err), err);
1001                        goto out;
1002                }
1003        }
1004
1005        err = bpf_linker__finalize(linker);
1006        if (err) {
1007                p_err("failed to finalize ELF file: %s (%d)", strerror(err), err);
1008                goto out;
1009        }
1010
1011        err = 0;
1012out:
1013        bpf_linker__free(linker);
1014        return err;
1015}
1016
1017static int do_help(int argc, char **argv)
1018{
1019        if (json_output) {
1020                jsonw_null(json_wtr);
1021                return 0;
1022        }
1023
1024        fprintf(stderr,
1025                "Usage: %1$s %2$s object OUTPUT_FILE INPUT_FILE [INPUT_FILE...]\n"
1026                "       %1$s %2$s skeleton FILE [name OBJECT_NAME]\n"
1027                "       %1$s %2$s help\n"
1028                "\n"
1029                "       " HELP_SPEC_OPTIONS " |\n"
1030                "                    {-L|--use-loader} }\n"
1031                "",
1032                bin_name, "gen");
1033
1034        return 0;
1035}
1036
1037static const struct cmd cmds[] = {
1038        { "object",     do_object },
1039        { "skeleton",   do_skeleton },
1040        { "help",       do_help },
1041        { 0 }
1042};
1043
1044int do_gen(int argc, char **argv)
1045{
1046        return cmd_select(cmds, argc, argv, do_help);
1047}
1048