|
1 | 1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
2 | 2 | /* Copyright (C) 2019 Facebook */
|
3 | 3 |
|
| 4 | +#ifndef _GNU_SOURCE |
| 5 | +#define _GNU_SOURCE |
| 6 | +#endif |
4 | 7 | #include <errno.h>
|
5 | 8 | #include <fcntl.h>
|
6 | 9 | #include <linux/err.h>
|
7 | 10 | #include <stdbool.h>
|
8 | 11 | #include <stdio.h>
|
| 12 | +#include <stdlib.h> |
9 | 13 | #include <string.h>
|
10 | 14 | #include <unistd.h>
|
11 | 15 | #include <linux/btf.h>
|
|
21 | 25 | #include "main.h"
|
22 | 26 |
|
23 | 27 | #define KFUNC_DECL_TAG "bpf_kfunc"
|
| 28 | +#define FASTCALL_DECL_TAG "bpf_fastcall" |
24 | 29 |
|
25 | 30 | static const char * const btf_kind_str[NR_BTF_KINDS] = {
|
26 | 31 | [BTF_KIND_UNKN] = "UNKNOWN",
|
@@ -464,47 +469,113 @@ static int dump_btf_raw(const struct btf *btf,
|
464 | 469 | return 0;
|
465 | 470 | }
|
466 | 471 |
|
| 472 | +struct ptr_array { |
| 473 | + __u32 cnt; |
| 474 | + __u32 cap; |
| 475 | + const void **elems; |
| 476 | +}; |
| 477 | + |
| 478 | +static int ptr_array_push(const void *ptr, struct ptr_array *arr) |
| 479 | +{ |
| 480 | + __u32 new_cap; |
| 481 | + void *tmp; |
| 482 | + |
| 483 | + if (arr->cnt == arr->cap) { |
| 484 | + new_cap = (arr->cap ?: 16) * 2; |
| 485 | + tmp = realloc(arr->elems, sizeof(*arr->elems) * new_cap); |
| 486 | + if (!tmp) |
| 487 | + return -ENOMEM; |
| 488 | + arr->elems = tmp; |
| 489 | + arr->cap = new_cap; |
| 490 | + } |
| 491 | + arr->elems[arr->cnt++] = ptr; |
| 492 | + return 0; |
| 493 | +} |
| 494 | + |
| 495 | +static void ptr_array_free(struct ptr_array *arr) |
| 496 | +{ |
| 497 | + free(arr->elems); |
| 498 | +} |
| 499 | + |
| 500 | +static int cmp_kfuncs(const void *pa, const void *pb, void *ctx) |
| 501 | +{ |
| 502 | + struct btf *btf = ctx; |
| 503 | + const struct btf_type *a = *(void **)pa; |
| 504 | + const struct btf_type *b = *(void **)pb; |
| 505 | + |
| 506 | + return strcmp(btf__str_by_offset(btf, a->name_off), |
| 507 | + btf__str_by_offset(btf, b->name_off)); |
| 508 | +} |
| 509 | + |
467 | 510 | static int dump_btf_kfuncs(struct btf_dump *d, const struct btf *btf)
|
468 | 511 | {
|
469 | 512 | LIBBPF_OPTS(btf_dump_emit_type_decl_opts, opts);
|
470 |
| - int cnt = btf__type_cnt(btf); |
471 |
| - int i; |
| 513 | + __u32 cnt = btf__type_cnt(btf), i, j; |
| 514 | + struct ptr_array fastcalls = {}; |
| 515 | + struct ptr_array kfuncs = {}; |
| 516 | + int err = 0; |
472 | 517 |
|
473 | 518 | printf("\n/* BPF kfuncs */\n");
|
474 | 519 | printf("#ifndef BPF_NO_KFUNC_PROTOTYPES\n");
|
475 | 520 |
|
476 | 521 | for (i = 1; i < cnt; i++) {
|
477 | 522 | const struct btf_type *t = btf__type_by_id(btf, i);
|
| 523 | + const struct btf_type *ft; |
478 | 524 | const char *name;
|
479 |
| - int err; |
480 | 525 |
|
481 | 526 | if (!btf_is_decl_tag(t))
|
482 | 527 | continue;
|
483 | 528 |
|
484 | 529 | if (btf_decl_tag(t)->component_idx != -1)
|
485 | 530 | continue;
|
486 | 531 |
|
487 |
| - name = btf__name_by_offset(btf, t->name_off); |
488 |
| - if (strncmp(name, KFUNC_DECL_TAG, sizeof(KFUNC_DECL_TAG))) |
| 532 | + ft = btf__type_by_id(btf, t->type); |
| 533 | + if (!btf_is_func(ft)) |
489 | 534 | continue;
|
490 | 535 |
|
491 |
| - t = btf__type_by_id(btf, t->type); |
492 |
| - if (!btf_is_func(t)) |
493 |
| - continue; |
| 536 | + name = btf__name_by_offset(btf, t->name_off); |
| 537 | + if (strncmp(name, KFUNC_DECL_TAG, sizeof(KFUNC_DECL_TAG)) == 0) { |
| 538 | + err = ptr_array_push(ft, &kfuncs); |
| 539 | + if (err) |
| 540 | + goto out; |
| 541 | + } |
| 542 | + |
| 543 | + if (strncmp(name, FASTCALL_DECL_TAG, sizeof(FASTCALL_DECL_TAG)) == 0) { |
| 544 | + err = ptr_array_push(ft, &fastcalls); |
| 545 | + if (err) |
| 546 | + goto out; |
| 547 | + } |
| 548 | + } |
| 549 | + |
| 550 | + /* Sort kfuncs by name for improved vmlinux.h stability */ |
| 551 | + qsort_r(kfuncs.elems, kfuncs.cnt, sizeof(*kfuncs.elems), cmp_kfuncs, (void *)btf); |
| 552 | + for (i = 0; i < kfuncs.cnt; i++) { |
| 553 | + const struct btf_type *t = kfuncs.elems[i]; |
494 | 554 |
|
495 | 555 | printf("extern ");
|
496 | 556 |
|
| 557 | + /* Assume small amount of fastcall kfuncs */ |
| 558 | + for (j = 0; j < fastcalls.cnt; j++) { |
| 559 | + if (fastcalls.elems[j] == t) { |
| 560 | + printf("__bpf_fastcall "); |
| 561 | + break; |
| 562 | + } |
| 563 | + } |
| 564 | + |
497 | 565 | opts.field_name = btf__name_by_offset(btf, t->name_off);
|
498 | 566 | err = btf_dump__emit_type_decl(d, t->type, &opts);
|
499 | 567 | if (err)
|
500 |
| - return err; |
| 568 | + goto out; |
501 | 569 |
|
502 | 570 | printf(" __weak __ksym;\n");
|
503 | 571 | }
|
504 | 572 |
|
505 | 573 | printf("#endif\n\n");
|
506 | 574 |
|
507 |
| - return 0; |
| 575 | +out: |
| 576 | + ptr_array_free(&fastcalls); |
| 577 | + ptr_array_free(&kfuncs); |
| 578 | + return err; |
508 | 579 | }
|
509 | 580 |
|
510 | 581 | static void __printf(2, 0) btf_dump_printf(void *ctx,
|
@@ -718,6 +789,13 @@ static int dump_btf_c(const struct btf *btf,
|
718 | 789 | printf("#ifndef __weak\n");
|
719 | 790 | printf("#define __weak __attribute__((weak))\n");
|
720 | 791 | printf("#endif\n\n");
|
| 792 | + printf("#ifndef __bpf_fastcall\n"); |
| 793 | + printf("#if __has_attribute(bpf_fastcall)\n"); |
| 794 | + printf("#define __bpf_fastcall __attribute__((bpf_fastcall))\n"); |
| 795 | + printf("#else\n"); |
| 796 | + printf("#define __bpf_fastcall\n"); |
| 797 | + printf("#endif\n"); |
| 798 | + printf("#endif\n\n"); |
721 | 799 |
|
722 | 800 | if (root_type_cnt) {
|
723 | 801 | for (i = 0; i < root_type_cnt; i++) {
|
|
0 commit comments