History

Merge branch 'bpftool-show-pid'

Andrii Nakryiko says: ==================== This patch set implements libbpf support for a second kind of special externs, kernel symbols, in addition to existing Kconfig externs. Right now, only untyped (const void) externs are supported, which, in C language, allow only to take their address. In the future, with kernel BTF getting type info about its own global and per-cpu variables, libbpf will extend this support with BTF type info, which will allow to also directly access variable's contents and follow its internal pointers, similarly to how it's possible today in fentry/fexit programs. As a first practical use of this functionality, bpftool gained ability to show PIDs of processes that have open file descriptors for BPF map/program/link/BTF object. It relies on iter/task_file BPF iterator program to extract this information efficiently. There was a bunch of bpftool refactoring (especially Makefile) necessary to generalize bpftool's internal BPF program use. This includes generalization of BPF skeletons support, addition of a vmlinux.h generation, extracting and building minimal subset of bpftool for bootstrapping. v2->v3: - fix sec_btf_id check (Hao); v1->v2: - docs fixes (Quentin); - dual GPL/BSD license for pid_inter.bpf.c (Quentin); - NULL-init kcfg_data (Hao Luo); rfc->v1: - show pids, if supported by kernel, always (Alexei); - switched iter output to binary to support showing process names; - update man pages; - fix few minor bugs in libbpf w.r.t. extern iteration. ====================

Alexei Starovoitov committed 6 years ago

Commit b3eece02 parents 1bdb6c9 075c77627 files · +1252 −547Browse files

Unified · Split

27 files
  1. tools/bpf/bpftool/.gitignore +3 −2
  2. tools/bpf/bpftool/Documentation/bpftool-btf.rst +5 −0
  3. tools/bpf/bpftool/Documentation/bpftool-link.rst +12 −1
  4. tools/bpf/bpftool/Documentation/bpftool-map.rst +7 −1
  5. tools/bpf/bpftool/Documentation/bpftool-prog.rst +11 −0
  6. tools/bpf/bpftool/Makefile +39 −21
  7. tools/bpf/bpftool/btf.c +6 −0
  8. tools/bpf/bpftool/common.c +308 −0
  9. tools/bpf/bpftool/link.c +7 −0
  10. tools/bpf/bpftool/main.c +10 −2
  11. tools/bpf/bpftool/main.h +44 −12
  12. tools/bpf/bpftool/map.c +7 −156
  13. tools/bpf/bpftool/pids.c +229 −0
  14. tools/bpf/bpftool/prog.c +7 −152
  15. tools/bpf/bpftool/skeleton/pid_iter.bpf.c +80 −0
  16. tools/bpf/bpftool/skeleton/pid_iter.h +12 −0
  17. tools/bpf/bpftool/skeleton/profiler.bpf.c +1 −2
  18. tools/bpf/bpftool/skeleton/profiler.h +0 −46
  19. tools/build/feature/Makefile +2 −2
  20. tools/build/feature/test-clang-bpf-co-re.c +9 −0
  21. tools/build/feature/test-clang-bpf-global-var.c +0 −4
  22. tools/lib/bpf/bpf_core_read.h +4 −4
  23. tools/lib/bpf/bpf_helpers.h +1 −0
  24. tools/lib/bpf/btf.h +5 −0
  25. tools/lib/bpf/libbpf.c +340 −142
  26. tools/testing/selftests/bpf/prog_tests/ksyms.c +71 −0
  27. tools/testing/selftests/bpf/progs/test_ksyms.c +32 −0
tools/bpf/bpftool/.gitignore+3−2
@@ -1,10 +1,11 @@
1# SPDX-License-Identifier: GPL-2.0-only1# SPDX-License-Identifier: GPL-2.0-only
2*.d2*.d
3/_bpftool3/bpftool-bootstrap
4/bpftool4/bpftool
5bpftool*.85bpftool*.8
6bpf-helpers.*6bpf-helpers.*
7FEATURE-DUMP.bpftool7FEATURE-DUMP.bpftool
8feature8feature
9libbpf9libbpf
10profiler.skel.h10/*.skel.h
11/vmlinux.h
tools/bpf/bpftool/Documentation/bpftool-btf.rst+5−0
@@ -36,6 +36,11 @@ DESCRIPTION · 35 unmodified lines
36 otherwise list all BTF objects currently loaded on the36 otherwise list all BTF objects currently loaded on the
37 system.37 system.
38 38
39 Since Linux 5.8 bpftool is able to discover information about
40 processes that hold open file descriptors (FDs) against BTF
41 objects. On such kernels bpftool will automatically emit this
42 information as well.
43
39 **bpftool btf dump** *BTF_SRC*44 **bpftool btf dump** *BTF_SRC*
40 Dump BTF entries from a given *BTF_SRC*.45 Dump BTF entries from a given *BTF_SRC*.
41 46
tools/bpf/bpftool/Documentation/bpftool-link.rst+12−1
@@ -37,6 +37,11 @@ DESCRIPTION · 36 unmodified lines
37 zero or more named attributes, some of which depend on type37 zero or more named attributes, some of which depend on type
38 of link.38 of link.
39 39
40 Since Linux 5.8 bpftool is able to discover information about
41 processes that hold open file descriptors (FDs) against BPF
42 links. On such kernels bpftool will automatically emit this
43 information as well.
44
40 **bpftool link pin** *LINK* *FILE*45 **bpftool link pin** *LINK* *FILE*
41 Pin link *LINK* as *FILE*.46 Pin link *LINK* as *FILE*.
42 47
@@ -82,6 +87,7 @@ EXAMPLES · 39 unmodified lines
82 87
83 10: cgroup prog 2588 10: cgroup prog 25
84 cgroup_id 614 attach_type egress89 cgroup_id 614 attach_type egress
90 pids test_progs(223)
85 91
86**# bpftool --json --pretty link show**92**# bpftool --json --pretty link show**
87 93
@@ -91,7 +97,12 @@ EXAMPLES · 3 unmodified lines
91 "type": "cgroup",97 "type": "cgroup",
92 "prog_id": 25,98 "prog_id": 25,
93 "cgroup_id": 614,99 "cgroup_id": 614,
94 "attach_type": "egress"100 "attach_type": "egress",
101 "pids": [{
102 "pid": 223,
103 "comm": "test_progs"
104 }
105 ]
95 }106 }
96 ]107 ]
97 108
tools/bpf/bpftool/Documentation/bpftool-map.rst+7−1
@@ -62,6 +62,11 @@ DESCRIPTION · 61 unmodified lines
62 Output will start with map ID followed by map type and62 Output will start with map ID followed by map type and
63 zero or more named attributes (depending on kernel version).63 zero or more named attributes (depending on kernel version).
64 64
65 Since Linux 5.8 bpftool is able to discover information about
66 processes that hold open file descriptors (FDs) against BPF
67 maps. On such kernels bpftool will automatically emit this
68 information as well.
69
65 **bpftool map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**dev** *NAME*]70 **bpftool map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**dev** *NAME*]
66 Create a new map with given parameters and pin it to *bpffs*71 Create a new map with given parameters and pin it to *bpffs*
67 as *FILE*.72 as *FILE*.
@@ -180,7 +185,8 @@ EXAMPLES · 112 unmodified lines
180::185::
181 186
182 10: hash name some_map flags 0x0187 10: hash name some_map flags 0x0
183 key 4B value 8B max_entries 2048 memlock 167936B188 key 4B value 8B max_entries 2048 memlock 167936B
189 pids systemd(1)
184 190
185The following three commands are equivalent:191The following three commands are equivalent:
186 192
tools/bpf/bpftool/Documentation/bpftool-prog.rst+11−0
@@ -75,6 +75,11 @@ DESCRIPTION · 74 unmodified lines
75 program run. Activation or deactivation of the feature is75 program run. Activation or deactivation of the feature is
76 performed via the **kernel.bpf_stats_enabled** sysctl knob.76 performed via the **kernel.bpf_stats_enabled** sysctl knob.
77 77
78 Since Linux 5.8 bpftool is able to discover information about
79 processes that hold open file descriptors (FDs) against BPF
80 programs. On such kernels bpftool will automatically emit this
81 information as well.
82
78 **bpftool prog dump xlated** *PROG* [{ **file** *FILE* | **opcodes** | **visual** | **linum** }]83 **bpftool prog dump xlated** *PROG* [{ **file** *FILE* | **opcodes** | **visual** | **linum** }]
79 Dump eBPF instructions of the programs from the kernel. By84 Dump eBPF instructions of the programs from the kernel. By
80 default, eBPF will be disassembled and printed to standard85 default, eBPF will be disassembled and printed to standard
@@ -243,6 +248,7 @@ EXAMPLES · 162 unmodified lines
243 10: xdp name some_prog tag 005a3d2123620c8b gpl run_time_ns 81632 run_cnt 10248 10: xdp name some_prog tag 005a3d2123620c8b gpl run_time_ns 81632 run_cnt 10
244 loaded_at 2017-09-29T20:11:00+0000 uid 0249 loaded_at 2017-09-29T20:11:00+0000 uid 0
245 xlated 528B jited 370B memlock 4096B map_ids 10250 xlated 528B jited 370B memlock 4096B map_ids 10
251 pids systemd(1)
246 252
247**# bpftool --json --pretty prog show**253**# bpftool --json --pretty prog show**
248 254
@@ -262,6 +268,11 @@ EXAMPLES · 13 unmodified lines
262 "bytes_jited": 370,268 "bytes_jited": 370,
263 "bytes_memlock": 4096,269 "bytes_memlock": 4096,
264 "map_ids": [10270 "map_ids": [10
271 ],
272 "pids": [{
273 "pid": 1,
274 "comm": "systemd"
275 }
265 ]276 ]
266 }277 }
267 ]278 ]
tools/bpf/bpftool/Makefile+39−21
@@ -42,6 +42,7 @@ CFLAGS += -O2 · 41 unmodified lines
42CFLAGS += -W -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers42CFLAGS += -W -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers
43CFLAGS += $(filter-out -Wswitch-enum,$(EXTRA_WARNINGS))43CFLAGS += $(filter-out -Wswitch-enum,$(EXTRA_WARNINGS))
44CFLAGS += -DPACKAGE='"bpftool"' -D__EXPORTED_HEADERS__ \44CFLAGS += -DPACKAGE='"bpftool"' -D__EXPORTED_HEADERS__ \
45 -I$(if $(OUTPUT),$(OUTPUT),.) \
45 -I$(srctree)/kernel/bpf/ \46 -I$(srctree)/kernel/bpf/ \
46 -I$(srctree)/tools/include \47 -I$(srctree)/tools/include \
47 -I$(srctree)/tools/include/uapi \48 -I$(srctree)/tools/include/uapi \
@@ -61,9 +62,9 @@ CLANG ?= clang · 13 unmodified lines
61 62
62FEATURE_USER = .bpftool63FEATURE_USER = .bpftool
63FEATURE_TESTS = libbfd disassembler-four-args reallocarray zlib libcap \64FEATURE_TESTS = libbfd disassembler-four-args reallocarray zlib libcap \
64 clang-bpf-global-var65 clang-bpf-co-re
65FEATURE_DISPLAY = libbfd disassembler-four-args zlib libcap \66FEATURE_DISPLAY = libbfd disassembler-four-args zlib libcap \
66 clang-bpf-global-var67 clang-bpf-co-re
67 68
68check_feat := 169check_feat := 1
69NON_CHECK_FEAT_TARGETS := clean uninstall doc doc-clean doc-install doc-uninstall70NON_CHECK_FEAT_TARGETS := clean uninstall doc doc-clean doc-install doc-uninstall
@@ -116,40 +117,56 @@ CFLAGS += -DHAVE_LIBBFD_SUPPORT · 46 unmodified lines
116SRCS += $(BFD_SRCS)117SRCS += $(BFD_SRCS)
117endif118endif
118 119
120BPFTOOL_BOOTSTRAP := $(if $(OUTPUT),$(OUTPUT)bpftool-bootstrap,./bpftool-bootstrap)
121
122BOOTSTRAP_OBJS = $(addprefix $(OUTPUT),main.o common.o json_writer.o gen.o btf.o)
119OBJS = $(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) $(OUTPUT)disasm.o123OBJS = $(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) $(OUTPUT)disasm.o
120_OBJS = $(filter-out $(OUTPUT)prog.o,$(OBJS)) $(OUTPUT)_prog.o
121 124
122ifeq ($(feature-clang-bpf-global-var),1)125VMLINUX_BTF_PATHS := $(if $(O),$(O)/vmlinux) \
123 __OBJS = $(OBJS)126 $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \
124else127 ../../../vmlinux \
125 __OBJS = $(_OBJS)128 /sys/kernel/btf/vmlinux \
126endif129 /boot/vmlinux-$(shell uname -r)
130VMLINUX_BTF := $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS))))
127 131
128$(OUTPUT)_prog.o: prog.c132ifneq ($(VMLINUX_BTF),)
129 $(QUIET_CC)$(CC) $(CFLAGS) -c -MMD -DBPFTOOL_WITHOUT_SKELETONS -o $@ $<133ifeq ($(feature-clang-bpf-co-re),1)
130 134
131$(OUTPUT)_bpftool: $(_OBJS) $(LIBBPF)135BUILD_BPF_SKELS := 1
132 $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(_OBJS) $(LIBS)
133 136
134skeleton/profiler.bpf.o: skeleton/profiler.bpf.c $(LIBBPF)137$(OUTPUT)vmlinux.h: $(VMLINUX_BTF) $(BPFTOOL_BOOTSTRAP)
138 $(QUIET_GEN)$(BPFTOOL_BOOTSTRAP) btf dump file $< format c > $@
139
140$(OUTPUT)%.bpf.o: skeleton/%.bpf.c $(OUTPUT)vmlinux.h $(LIBBPF)
135 $(QUIET_CLANG)$(CLANG) \141 $(QUIET_CLANG)$(CLANG) \
142 -I$(if $(OUTPUT),$(OUTPUT),.) \
136 -I$(srctree)/tools/include/uapi/ \143 -I$(srctree)/tools/include/uapi/ \
137 -I$(LIBBPF_PATH) -I$(srctree)/tools/lib \144 -I$(LIBBPF_PATH) \
145 -I$(srctree)/tools/lib \
138 -g -O2 -target bpf -c $< -o $@146 -g -O2 -target bpf -c $< -o $@
139 147
140profiler.skel.h: $(OUTPUT)_bpftool skeleton/profiler.bpf.o148$(OUTPUT)%.skel.h: $(OUTPUT)%.bpf.o $(BPFTOOL_BOOTSTRAP)
141 $(QUIET_GEN)$(OUTPUT)./_bpftool gen skeleton skeleton/profiler.bpf.o > $@149 $(QUIET_GEN)$(BPFTOOL_BOOTSTRAP) gen skeleton $< > $@
142 150
143$(OUTPUT)prog.o: prog.c profiler.skel.h151$(OUTPUT)prog.o: $(OUTPUT)profiler.skel.h
144 $(QUIET_CC)$(CC) $(CFLAGS) -c -MMD -o $@ $<152
153$(OUTPUT)pids.o: $(OUTPUT)pid_iter.skel.h
154
155endif
156endif
157
158CFLAGS += $(if BUILD_BPF_SKELS,,-DBPFTOOL_WITHOUT_SKELETONS)
145 159
146$(OUTPUT)disasm.o: $(srctree)/kernel/bpf/disasm.c160$(OUTPUT)disasm.o: $(srctree)/kernel/bpf/disasm.c
147 $(QUIET_CC)$(CC) $(CFLAGS) -c -MMD -o $@ $<161 $(QUIET_CC)$(CC) $(CFLAGS) -c -MMD -o $@ $<
148 162
149$(OUTPUT)feature.o: | zdep163$(OUTPUT)feature.o: | zdep
150 164
151$(OUTPUT)bpftool: $(__OBJS) $(LIBBPF)165$(BPFTOOL_BOOTSTRAP): $(BOOTSTRAP_OBJS) $(LIBBPF)
152 $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(__OBJS) $(LIBS)166 $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(BOOTSTRAP_OBJS) $(LIBS)
167
168$(OUTPUT)bpftool: $(OBJS) $(LIBBPF)
169 $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
153 170
154$(OUTPUT)%.o: %.c171$(OUTPUT)%.o: %.c
155 $(QUIET_CC)$(CC) $(CFLAGS) -c -MMD -o $@ $<172 $(QUIET_CC)$(CC) $(CFLAGS) -c -MMD -o $@ $<
@@ -157,7 +174,7 @@ $(OUTPUT)%.o: %.c · 1 unmodified line
157clean: $(LIBBPF)-clean174clean: $(LIBBPF)-clean
158 $(call QUIET_CLEAN, bpftool)175 $(call QUIET_CLEAN, bpftool)
159 $(Q)$(RM) -- $(OUTPUT)bpftool $(OUTPUT)*.o $(OUTPUT)*.d176 $(Q)$(RM) -- $(OUTPUT)bpftool $(OUTPUT)*.o $(OUTPUT)*.d
160 $(Q)$(RM) -- $(OUTPUT)_bpftool profiler.skel.h skeleton/profiler.bpf.o177 $(Q)$(RM) -- $(BPFTOOL_BOOTSTRAP) $(OUTPUT)*.skel.h $(OUTPUT)vmlinux.h
161 $(Q)$(RM) -r -- $(OUTPUT)libbpf/178 $(Q)$(RM) -r -- $(OUTPUT)libbpf/
162 $(call QUIET_CLEAN, core-gen)179 $(call QUIET_CLEAN, core-gen)
163 $(Q)$(RM) -- $(OUTPUT)FEATURE-DUMP.bpftool180 $(Q)$(RM) -- $(OUTPUT)FEATURE-DUMP.bpftool
@@ -192,6 +209,7 @@ FORCE: · 28 unmodified lines
192zdep:209zdep:
193 @if [ "$(feature-zlib)" != "1" ]; then echo "No zlib found"; exit 1 ; fi210 @if [ "$(feature-zlib)" != "1" ]; then echo "No zlib found"; exit 1 ; fi
194 211
212.SECONDARY:
195.PHONY: all FORCE clean install uninstall zdep213.PHONY: all FORCE clean install uninstall zdep
196.PHONY: doc doc-clean doc-install doc-uninstall214.PHONY: doc doc-clean doc-install doc-uninstall
197.DEFAULT_GOAL := all215.DEFAULT_GOAL := all
tools/bpf/bpftool/btf.c+6−0
@@ -809,6 +809,7 @@ show_btf_plain(struct bpf_btf_info *info, int fd, · 808 unmodified lines
809 printf("%s%u", n++ == 0 ? " map_ids " : ",",809 printf("%s%u", n++ == 0 ? " map_ids " : ",",
810 obj->obj_id);810 obj->obj_id);
811 }811 }
812 emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");
812 813
813 printf("\n");814 printf("\n");
814}815}
@@ -841,6 +842,9 @@ show_btf_json(struct bpf_btf_info *info, int fd, · 26 unmodified lines
841 jsonw_uint(json_wtr, obj->obj_id);842 jsonw_uint(json_wtr, obj->obj_id);
842 }843 }
843 jsonw_end_array(json_wtr); /* map_ids */844 jsonw_end_array(json_wtr); /* map_ids */
845
846 emit_obj_refs_json(&refs_table, info->id, json_wtr); /* pids */
847
844 jsonw_end_object(json_wtr); /* btf object */848 jsonw_end_object(json_wtr); /* btf object */
845}849}
846 850
@@ -893,6 +897,7 @@ static int do_show(int argc, char **argv) · 46 unmodified lines
893 close(fd);897 close(fd);
894 return err;898 return err;
895 }899 }
900 build_obj_refs_table(&refs_table, BPF_OBJ_BTF);
896 901
897 if (fd >= 0) {902 if (fd >= 0) {
898 err = show_btf(fd, &btf_prog_table, &btf_map_table);903 err = show_btf(fd, &btf_prog_table, &btf_map_table);
@@ -939,6 +944,7 @@ static int do_show(int argc, char **argv) · 40 unmodified lines
939exit_free:944exit_free:
940 delete_btf_table(&btf_prog_table);945 delete_btf_table(&btf_prog_table);
941 delete_btf_table(&btf_map_table);946 delete_btf_table(&btf_map_table);
947 delete_obj_refs_table(&refs_table);
942 948
943 return err;949 return err;
944}950}
tools/bpf/bpftool/common.c+308−0
@@ -581,3 +581,311 @@ print_all_levels(__maybe_unused enum libbpf_print_level level, · 580 unmodified lines
581{581{
582 return vfprintf(stderr, format, args);582 return vfprintf(stderr, format, args);
583}583}
584
585static int prog_fd_by_nametag(void *nametag, int **fds, bool tag)
586{
587 unsigned int id = 0;
588 int fd, nb_fds = 0;
589 void *tmp;
590 int err;
591
592 while (true) {
593 struct bpf_prog_info info = {};
594 __u32 len = sizeof(info);
595
596 err = bpf_prog_get_next_id(id, &id);
597 if (err) {
598 if (errno != ENOENT) {
599 p_err("%s", strerror(errno));
600 goto err_close_fds;
601 }
602 return nb_fds;
603 }
604
605 fd = bpf_prog_get_fd_by_id(id);
606 if (fd < 0) {
607 p_err("can't get prog by id (%u): %s",
608 id, strerror(errno));
609 goto err_close_fds;
610 }
611
612 err = bpf_obj_get_info_by_fd(fd, &info, &len);
613 if (err) {
614 p_err("can't get prog info (%u): %s",
615 id, strerror(errno));
616 goto err_close_fd;
617 }
618
619 if ((tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) ||
620 (!tag && strncmp(nametag, info.name, BPF_OBJ_NAME_LEN))) {
621 close(fd);
622 continue;
623 }
624
625 if (nb_fds > 0) {
626 tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
627 if (!tmp) {
628 p_err("failed to realloc");
629 goto err_close_fd;
630 }
631 *fds = tmp;
632 }
633 (*fds)[nb_fds++] = fd;
634 }
635
636err_close_fd:
637 close(fd);
638err_close_fds:
639 while (--nb_fds >= 0)
640 close((*fds)[nb_fds]);
641 return -1;
642}
643
644int prog_parse_fds(int *argc, char ***argv, int **fds)
645{
646 if (is_prefix(**argv, "id")) {
647 unsigned int id;
648 char *endptr;
649
650 NEXT_ARGP();
651
652 id = strtoul(**argv, &endptr, 0);
653 if (*endptr) {
654 p_err("can't parse %s as ID", **argv);
655 return -1;
656 }
657 NEXT_ARGP();
658
659 (*fds)[0] = bpf_prog_get_fd_by_id(id);
660 if ((*fds)[0] < 0) {
661 p_err("get by id (%u): %s", id, strerror(errno));
662 return -1;
663 }
664 return 1;
665 } else if (is_prefix(**argv, "tag")) {
666 unsigned char tag[BPF_TAG_SIZE];
667
668 NEXT_ARGP();
669
670 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2,
671 tag + 3, tag + 4, tag + 5, tag + 6, tag + 7)
672 != BPF_TAG_SIZE) {
673 p_err("can't parse tag");
674 return -1;
675 }
676 NEXT_ARGP();
677
678 return prog_fd_by_nametag(tag, fds, true);
679 } else if (is_prefix(**argv, "name")) {
680 char *name;
681
682 NEXT_ARGP();
683
684 name = **argv;
685 if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
686 p_err("can't parse name");
687 return -1;
688 }
689 NEXT_ARGP();
690
691 return prog_fd_by_nametag(name, fds, false);
692 } else if (is_prefix(**argv, "pinned")) {
693 char *path;
694
695 NEXT_ARGP();
696
697 path = **argv;
698 NEXT_ARGP();
699
700 (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG);
701 if ((*fds)[0] < 0)
702 return -1;
703 return 1;
704 }
705
706 p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv);
707 return -1;
708}
709
710int prog_parse_fd(int *argc, char ***argv)
711{
712 int *fds = NULL;
713 int nb_fds, fd;
714
715 fds = malloc(sizeof(int));
716 if (!fds) {
717 p_err("mem alloc failed");
718 return -1;
719 }
720 nb_fds = prog_parse_fds(argc, argv, &fds);
721 if (nb_fds != 1) {
722 if (nb_fds > 1) {
723 p_err("several programs match this handle");
724 while (nb_fds--)
725 close(fds[nb_fds]);
726 }
727 fd = -1;
728 goto exit_free;
729 }
730
731 fd = fds[0];
732exit_free:
733 free(fds);
734 return fd;
735}
736
737static int map_fd_by_name(char *name, int **fds)
738{
739 unsigned int id = 0;
740 int fd, nb_fds = 0;
741 void *tmp;
742 int err;
743
744 while (true) {
745 struct bpf_map_info info = {};
746 __u32 len = sizeof(info);
747
748 err = bpf_map_get_next_id(id, &id);
749 if (err) {
750 if (errno != ENOENT) {
751 p_err("%s", strerror(errno));
752 goto err_close_fds;
753 }
754 return nb_fds;
755 }
756
757 fd = bpf_map_get_fd_by_id(id);
758 if (fd < 0) {
759 p_err("can't get map by id (%u): %s",
760 id, strerror(errno));
761 goto err_close_fds;
762 }
763
764 err = bpf_obj_get_info_by_fd(fd, &info, &len);
765 if (err) {
766 p_err("can't get map info (%u): %s",
767 id, strerror(errno));
768 goto err_close_fd;
769 }
770
771 if (strncmp(name, info.name, BPF_OBJ_NAME_LEN)) {
772 close(fd);
773 continue;
774 }
775
776 if (nb_fds > 0) {
777 tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
778 if (!tmp) {
779 p_err("failed to realloc");
780 goto err_close_fd;
781 }
782 *fds = tmp;
783 }
784 (*fds)[nb_fds++] = fd;
785 }
786
787err_close_fd:
788 close(fd);
789err_close_fds:
790 while (--nb_fds >= 0)
791 close((*fds)[nb_fds]);
792 return -1;
793}
794
795int map_parse_fds(int *argc, char ***argv, int **fds)
796{
797 if (is_prefix(**argv, "id")) {
798 unsigned int id;
799 char *endptr;
800
801 NEXT_ARGP();
802
803 id = strtoul(**argv, &endptr, 0);
804 if (*endptr) {
805 p_err("can't parse %s as ID", **argv);
806 return -1;
807 }
808 NEXT_ARGP();
809
810 (*fds)[0] = bpf_map_get_fd_by_id(id);
811 if ((*fds)[0] < 0) {
812 p_err("get map by id (%u): %s", id, strerror(errno));
813 return -1;
814 }
815 return 1;
816 } else if (is_prefix(**argv, "name")) {
817 char *name;
818
819 NEXT_ARGP();
820
821 name = **argv;
822 if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
823 p_err("can't parse name");
824 return -1;
825 }
826 NEXT_ARGP();
827
828 return map_fd_by_name(name, fds);
829 } else if (is_prefix(**argv, "pinned")) {
830 char *path;
831
832 NEXT_ARGP();
833
834 path = **argv;
835 NEXT_ARGP();
836
837 (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_MAP);
838 if ((*fds)[0] < 0)
839 return -1;
840 return 1;
841 }
842
843 p_err("expected 'id', 'name' or 'pinned', got: '%s'?", **argv);
844 return -1;
845}
846
847int map_parse_fd(int *argc, char ***argv)
848{
849 int *fds = NULL;
850 int nb_fds, fd;
851
852 fds = malloc(sizeof(int));
853 if (!fds) {
854 p_err("mem alloc failed");
855 return -1;
856 }
857 nb_fds = map_parse_fds(argc, argv, &fds);
858 if (nb_fds != 1) {
859 if (nb_fds > 1) {
860 p_err("several maps match this handle");
861 while (nb_fds--)
862 close(fds[nb_fds]);
863 }
864 fd = -1;
865 goto exit_free;
866 }
867
868 fd = fds[0];
869exit_free:
870 free(fds);
871 return fd;
872}
873
874int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
875{
876 int err;
877 int fd;
878
879 fd = map_parse_fd(argc, argv);
880 if (fd < 0)
881 return -1;
882
883 err = bpf_obj_get_info_by_fd(fd, info, info_len);
884 if (err) {
885 p_err("can't get map info: %s", strerror(errno));
886 close(fd);
887 return err;
888 }
889
890 return fd;
891}
tools/bpf/bpftool/link.c+7−0
@@ -143,6 +143,9 @@ static int show_link_close_json(int fd, struct bpf_link_info *info) · 142 unmodified lines
143 }143 }
144 jsonw_end_array(json_wtr);144 jsonw_end_array(json_wtr);
145 }145 }
146
147 emit_obj_refs_json(&refs_table, info->id, json_wtr);
148
146 jsonw_end_object(json_wtr);149 jsonw_end_object(json_wtr);
147 150
148 return 0;151 return 0;
@@ -212,6 +215,7 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info) · 63 unmodified lines
212 printf("\n\tpinned %s", obj->path);215 printf("\n\tpinned %s", obj->path);
213 }216 }
214 }217 }
218 emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");
215 219
216 printf("\n");220 printf("\n");
217 221
@@ -257,6 +261,7 @@ static int do_show(int argc, char **argv) · 39 unmodified lines
257 261
258 if (show_pinned)262 if (show_pinned)
259 build_pinned_obj_table(&link_table, BPF_OBJ_LINK);263 build_pinned_obj_table(&link_table, BPF_OBJ_LINK);
264 build_obj_refs_table(&refs_table, BPF_OBJ_LINK);
260 265
261 if (argc == 2) {266 if (argc == 2) {
262 fd = link_parse_fd(&argc, &argv);267 fd = link_parse_fd(&argc, &argv);
@@ -296,6 +301,8 @@ static int do_show(int argc, char **argv) · 33 unmodified lines
296 if (json_output)301 if (json_output)
297 jsonw_end_array(json_wtr);302 jsonw_end_array(json_wtr);
298 303
304 delete_obj_refs_table(&refs_table);
305
299 return errno == ENOENT ? 0 : -1;306 return errno == ENOENT ? 0 : -1;
300}307}
301 308
tools/bpf/bpftool/main.c+10−2
@@ -31,6 +31,7 @@ bool relaxed_maps; · 30 unmodified lines
31struct pinned_obj_table prog_table;31struct pinned_obj_table prog_table;
32struct pinned_obj_table map_table;32struct pinned_obj_table map_table;
33struct pinned_obj_table link_table;33struct pinned_obj_table link_table;
34struct obj_refs_table refs_table;
34 35
35static void __noreturn clean_and_exit(int i)36static void __noreturn clean_and_exit(int i)
36{37{
@@ -92,9 +93,16 @@ int cmd_select(const struct cmd *cmds, int argc, char **argv, · 55 unmodified lines
92 if (argc < 1 && cmds[0].func)93 if (argc < 1 && cmds[0].func)
93 return cmds[0].func(argc, argv);94 return cmds[0].func(argc, argv);
94 95
95 for (i = 0; cmds[i].func; i++)96 for (i = 0; cmds[i].cmd; i++) {
96 if (is_prefix(*argv, cmds[i].cmd))97 if (is_prefix(*argv, cmds[i].cmd)) {
98 if (!cmds[i].func) {
99 p_err("command '%s' is not supported in bootstrap mode",
100 cmds[i].cmd);
101 return -1;
102 }
97 return cmds[i].func(argc - 1, argv + 1);103 return cmds[i].func(argc - 1, argv + 1);
104 }
105 }
98 106
99 help(argc - 1, argv + 1);107 help(argc - 1, argv + 1);
100 108
tools/bpf/bpftool/main.h+44−12
@@ -127,11 +127,13 @@ static const char * const attach_type_name[__MAX_BPF_ATTACH_TYPE] = { · 126 unmodified lines
127extern const char * const map_type_name[];127extern const char * const map_type_name[];
128extern const size_t map_type_name_size;128extern const size_t map_type_name_size;
129 129
130/* keep in sync with the definition in skeleton/pid_iter.bpf.c */
130enum bpf_obj_type {131enum bpf_obj_type {
131 BPF_OBJ_UNKNOWN,132 BPF_OBJ_UNKNOWN,
132 BPF_OBJ_PROG,133 BPF_OBJ_PROG,
133 BPF_OBJ_MAP,134 BPF_OBJ_MAP,
134 BPF_OBJ_LINK,135 BPF_OBJ_LINK,
136 BPF_OBJ_BTF,
135};137};
136 138
137extern const char *bin_name;139extern const char *bin_name;
@@ -139,12 +141,14 @@ extern const char *bin_name; · 1 unmodified line
139extern json_writer_t *json_wtr;141extern json_writer_t *json_wtr;
140extern bool json_output;142extern bool json_output;
141extern bool show_pinned;143extern bool show_pinned;
144extern bool show_pids;
142extern bool block_mount;145extern bool block_mount;
143extern bool verifier_logs;146extern bool verifier_logs;
144extern bool relaxed_maps;147extern bool relaxed_maps;
145extern struct pinned_obj_table prog_table;148extern struct pinned_obj_table prog_table;
146extern struct pinned_obj_table map_table;149extern struct pinned_obj_table map_table;
147extern struct pinned_obj_table link_table;150extern struct pinned_obj_table link_table;
151extern struct obj_refs_table refs_table;
148 152
149void __printf(1, 2) p_err(const char *fmt, ...);153void __printf(1, 2) p_err(const char *fmt, ...);
150void __printf(1, 2) p_info(const char *fmt, ...);154void __printf(1, 2) p_info(const char *fmt, ...);
@@ -168,12 +172,35 @@ struct pinned_obj { · 17 unmodified lines
168 struct hlist_node hash;172 struct hlist_node hash;
169};173};
170 174
175struct obj_refs_table {
176 DECLARE_HASHTABLE(table, 16);
177};
178
179struct obj_ref {
180 int pid;
181 char comm[16];
182};
183
184struct obj_refs {
185 struct hlist_node node;
186 __u32 id;
187 int ref_cnt;
188 struct obj_ref *refs;
189};
190
171struct btf;191struct btf;
172struct bpf_line_info;192struct bpf_line_info;
173 193
174int build_pinned_obj_table(struct pinned_obj_table *table,194int build_pinned_obj_table(struct pinned_obj_table *table,
175 enum bpf_obj_type type);195 enum bpf_obj_type type);
176void delete_pinned_obj_table(struct pinned_obj_table *tab);196void delete_pinned_obj_table(struct pinned_obj_table *tab);
197__weak int build_obj_refs_table(struct obj_refs_table *table,
198 enum bpf_obj_type type);
199__weak void delete_obj_refs_table(struct obj_refs_table *table);
200__weak void emit_obj_refs_json(struct obj_refs_table *table, __u32 id,
201 json_writer_t *json_wtr);
202__weak void emit_obj_refs_plain(struct obj_refs_table *table, __u32 id,
203 const char *prefix);
177void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode);204void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode);
178void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode);205void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode);
179 206
@@ -194,23 +221,28 @@ int mount_bpffs_for_pin(const char *name); · 14 unmodified lines
194int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(int *, char ***));221int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(int *, char ***));
195int do_pin_fd(int fd, const char *name);222int do_pin_fd(int fd, const char *name);
196 223
197int do_prog(int argc, char **arg);224/* commands available in bootstrap mode */
198int do_map(int argc, char **arg);
199int do_link(int argc, char **arg);
200int do_event_pipe(int argc, char **argv);
201int do_cgroup(int argc, char **arg);
202int do_perf(int argc, char **arg);
203int do_net(int argc, char **arg);
204int do_tracelog(int argc, char **arg);
205int do_feature(int argc, char **argv);
206int do_btf(int argc, char **argv);
207int do_gen(int argc, char **argv);225int do_gen(int argc, char **argv);
208int do_struct_ops(int argc, char **argv);226int do_btf(int argc, char **argv);
209int do_iter(int argc, char **argv);227
228/* non-bootstrap only commands */
229int do_prog(int argc, char **arg) __weak;
230int do_map(int argc, char **arg) __weak;
231int do_link(int argc, char **arg) __weak;
232int do_event_pipe(int argc, char **argv) __weak;
233int do_cgroup(int argc, char **arg) __weak;
234int do_perf(int argc, char **arg) __weak;
235int do_net(int argc, char **arg) __weak;
236int do_tracelog(int argc, char **arg) __weak;
237int do_feature(int argc, char **argv) __weak;
238int do_struct_ops(int argc, char **argv) __weak;
239int do_iter(int argc, char **argv) __weak;
210 240
211int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what);241int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what);
212int prog_parse_fd(int *argc, char ***argv);242int prog_parse_fd(int *argc, char ***argv);
243int prog_parse_fds(int *argc, char ***argv, int **fds);
213int map_parse_fd(int *argc, char ***argv);244int map_parse_fd(int *argc, char ***argv);
245int map_parse_fds(int *argc, char ***argv, int **fds);
214int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len);246int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len);
215 247
216struct bpf_prog_linfo;248struct bpf_prog_linfo;
tools/bpf/bpftool/map.c+7−156
@@ -92,162 +92,6 @@ static void *alloc_value(struct bpf_map_info *info) · 91 unmodified lines
92 return malloc(info->value_size);92 return malloc(info->value_size);
93}93}
94 94
95static int map_fd_by_name(char *name, int **fds)
96{
97 unsigned int id = 0;
98 int fd, nb_fds = 0;
99 void *tmp;
100 int err;
101
102 while (true) {
103 struct bpf_map_info info = {};
104 __u32 len = sizeof(info);
105
106 err = bpf_map_get_next_id(id, &id);
107 if (err) {
108 if (errno != ENOENT) {
109 p_err("%s", strerror(errno));
110 goto err_close_fds;
111 }
112 return nb_fds;
113 }
114
115 fd = bpf_map_get_fd_by_id(id);
116 if (fd < 0) {
117 p_err("can't get map by id (%u): %s",
118 id, strerror(errno));
119 goto err_close_fds;
120 }
121
122 err = bpf_obj_get_info_by_fd(fd, &info, &len);
123 if (err) {
124 p_err("can't get map info (%u): %s",
125 id, strerror(errno));
126 goto err_close_fd;
127 }
128
129 if (strncmp(name, info.name, BPF_OBJ_NAME_LEN)) {
130 close(fd);
131 continue;
132 }
133
134 if (nb_fds > 0) {
135 tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
136 if (!tmp) {
137 p_err("failed to realloc");
138 goto err_close_fd;
139 }
140 *fds = tmp;
141 }
142 (*fds)[nb_fds++] = fd;
143 }
144
145err_close_fd:
146 close(fd);
147err_close_fds:
148 while (--nb_fds >= 0)
149 close((*fds)[nb_fds]);
150 return -1;
151}
152
153static int map_parse_fds(int *argc, char ***argv, int **fds)
154{
155 if (is_prefix(**argv, "id")) {
156 unsigned int id;
157 char *endptr;
158
159 NEXT_ARGP();
160
161 id = strtoul(**argv, &endptr, 0);
162 if (*endptr) {
163 p_err("can't parse %s as ID", **argv);
164 return -1;
165 }
166 NEXT_ARGP();
167
168 (*fds)[0] = bpf_map_get_fd_by_id(id);
169 if ((*fds)[0] < 0) {
170 p_err("get map by id (%u): %s", id, strerror(errno));
171 return -1;
172 }
173 return 1;
174 } else if (is_prefix(**argv, "name")) {
175 char *name;
176
177 NEXT_ARGP();
178
179 name = **argv;
180 if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
181 p_err("can't parse name");
182 return -1;
183 }
184 NEXT_ARGP();
185
186 return map_fd_by_name(name, fds);
187 } else if (is_prefix(**argv, "pinned")) {
188 char *path;
189
190 NEXT_ARGP();
191
192 path = **argv;
193 NEXT_ARGP();
194
195 (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_MAP);
196 if ((*fds)[0] < 0)
197 return -1;
198 return 1;
199 }
200
201 p_err("expected 'id', 'name' or 'pinned', got: '%s'?", **argv);
202 return -1;
203}
204
205int map_parse_fd(int *argc, char ***argv)
206{
207 int *fds = NULL;
208 int nb_fds, fd;
209
210 fds = malloc(sizeof(int));
211 if (!fds) {
212 p_err("mem alloc failed");
213 return -1;
214 }
215 nb_fds = map_parse_fds(argc, argv, &fds);
216 if (nb_fds != 1) {
217 if (nb_fds > 1) {
218 p_err("several maps match this handle");
219 while (nb_fds--)
220 close(fds[nb_fds]);
221 }
222 fd = -1;
223 goto exit_free;
224 }
225
226 fd = fds[0];
227exit_free:
228 free(fds);
229 return fd;
230}
231
232int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
233{
234 int err;
235 int fd;
236
237 fd = map_parse_fd(argc, argv);
238 if (fd < 0)
239 return -1;
240
241 err = bpf_obj_get_info_by_fd(fd, info, info_len);
242 if (err) {
243 p_err("can't get map info: %s", strerror(errno));
244 close(fd);
245 return err;
246 }
247
248 return fd;
249}
250
251static int do_dump_btf(const struct btf_dumper *d,95static int do_dump_btf(const struct btf_dumper *d,
252 struct bpf_map_info *map_info, void *key,96 struct bpf_map_info *map_info, void *key,
253 void *value)97 void *value)
@@ -665,6 +509,8 @@ static int show_map_close_json(int fd, struct bpf_map_info *info) · 411 unmodified lines
665 jsonw_end_array(json_wtr);509 jsonw_end_array(json_wtr);
666 }510 }
667 511
512 emit_obj_refs_json(&refs_table, info->id, json_wtr);
513
668 jsonw_end_object(json_wtr);514 jsonw_end_object(json_wtr);
669 515
670 return 0;516 return 0;
@@ -752,6 +598,8 @@ static int show_map_close_plain(int fd, struct bpf_map_info *info) · 81 unmodified lines
752 if (frozen)598 if (frozen)
753 printf("%sfrozen", info->btf_id ? " " : "");599 printf("%sfrozen", info->btf_id ? " " : "");
754 600
601 emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");
602
755 printf("\n");603 printf("\n");
756 return 0;604 return 0;
757}605}
@@ -810,6 +658,7 @@ static int do_show(int argc, char **argv) · 52 unmodified lines
810 658
811 if (show_pinned)659 if (show_pinned)
812 build_pinned_obj_table(&map_table, BPF_OBJ_MAP);660 build_pinned_obj_table(&map_table, BPF_OBJ_MAP);
661 build_obj_refs_table(&refs_table, BPF_OBJ_MAP);
813 662
814 if (argc == 2)663 if (argc == 2)
815 return do_show_subset(argc, argv);664 return do_show_subset(argc, argv);
@@ -853,6 +702,8 @@ static int do_show(int argc, char **argv) · 37 unmodified lines
853 if (json_output)702 if (json_output)
854 jsonw_end_array(json_wtr);703 jsonw_end_array(json_wtr);
855 704
705 delete_obj_refs_table(&refs_table);
706
856 return errno == ENOENT ? 0 : -1;707 return errno == ENOENT ? 0 : -1;
857}708}
858 709
tools/bpf/bpftool/pids.c+229−0
@@ -0,0 +1,229 @@
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2/* Copyright (C) 2020 Facebook */
3#include <errno.h>
4#include <stdbool.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <unistd.h>
9#include <bpf/bpf.h>
10
11#include "main.h"
12#include "skeleton/pid_iter.h"
13
14#ifdef BPFTOOL_WITHOUT_SKELETONS
15
16int build_obj_refs_table(struct obj_refs_table *table, enum bpf_obj_type type)
17{
18 p_err("bpftool built without PID iterator support");
19 return -ENOTSUP;
20}
21void delete_obj_refs_table(struct obj_refs_table *table) {}
22
23#else /* BPFTOOL_WITHOUT_SKELETONS */
24
25#include "pid_iter.skel.h"
26
27static void add_ref(struct obj_refs_table *table, struct pid_iter_entry *e)
28{
29 struct obj_refs *refs;
30 struct obj_ref *ref;
31 void *tmp;
32 int i;
33
34 hash_for_each_possible(table->table, refs, node, e->id) {
35 if (refs->id != e->id)
36 continue;
37
38 for (i = 0; i < refs->ref_cnt; i++) {
39 if (refs->refs[i].pid == e->pid)
40 return;
41 }
42
43 tmp = realloc(refs->refs, (refs->ref_cnt + 1) * sizeof(*ref));
44 if (!tmp) {
45 p_err("failed to re-alloc memory for ID %u, PID %d, COMM %s...",
46 e->id, e->pid, e->comm);
47 return;
48 }
49 refs->refs = tmp;
50 ref = &refs->refs[refs->ref_cnt];
51 ref->pid = e->pid;
52 memcpy(ref->comm, e->comm, sizeof(ref->comm));
53 refs->ref_cnt++;
54
55 return;
56 }
57
58 /* new ref */
59 refs = calloc(1, sizeof(*refs));
60 if (!refs) {
61 p_err("failed to alloc memory for ID %u, PID %d, COMM %s...",
62 e->id, e->pid, e->comm);
63 return;
64 }
65
66 refs->id = e->id;
67 refs->refs = malloc(sizeof(*refs->refs));
68 if (!refs->refs) {
69 free(refs);
70 p_err("failed to alloc memory for ID %u, PID %d, COMM %s...",
71 e->id, e->pid, e->comm);
72 return;
73 }
74 ref = &refs->refs[0];
75 ref->pid = e->pid;
76 memcpy(ref->comm, e->comm, sizeof(ref->comm));
77 refs->ref_cnt = 1;
78 hash_add(table->table, &refs->node, e->id);
79}
80
81static int __printf(2, 0)
82libbpf_print_none(__maybe_unused enum libbpf_print_level level,
83 __maybe_unused const char *format,
84 __maybe_unused va_list args)
85{
86 return 0;
87}
88
89int build_obj_refs_table(struct obj_refs_table *table, enum bpf_obj_type type)
90{
91 char buf[4096];
92 struct pid_iter_bpf *skel;
93 struct pid_iter_entry *e;
94 int err, ret, fd = -1, i;
95 libbpf_print_fn_t default_print;
96
97 hash_init(table->table);
98 set_max_rlimit();
99
100 skel = pid_iter_bpf__open();
101 if (!skel) {
102 p_err("failed to open PID iterator skeleton");
103 return -1;
104 }
105
106 skel->rodata->obj_type = type;
107
108 /* we don't want output polluted with libbpf errors if bpf_iter is not
109 * supported
110 */
111 default_print = libbpf_set_print(libbpf_print_none);
112 err = pid_iter_bpf__load(skel);
113 libbpf_set_print(default_print);
114 if (err) {
115 /* too bad, kernel doesn't support BPF iterators yet */
116 err = 0;
117 goto out;
118 }
119 err = pid_iter_bpf__attach(skel);
120 if (err) {
121 /* if we loaded above successfully, attach has to succeed */
122 p_err("failed to attach PID iterator: %d", err);
123 goto out;
124 }
125
126 fd = bpf_iter_create(bpf_link__fd(skel->links.iter));
127 if (fd < 0) {
128 err = -errno;
129 p_err("failed to create PID iterator session: %d", err);
130 goto out;
131 }
132
133 while (true) {
134 ret = read(fd, buf, sizeof(buf));
135 if (ret < 0) {
136 err = -errno;
137 p_err("failed to read PID iterator output: %d", err);
138 goto out;
139 }
140 if (ret == 0)
141 break;
142 if (ret % sizeof(*e)) {
143 err = -EINVAL;
144 p_err("invalid PID iterator output format");
145 goto out;
146 }
147 ret /= sizeof(*e);
148
149 e = (void *)buf;
150 for (i = 0; i < ret; i++, e++) {
151 add_ref(table, e);
152 }
153 }
154 err = 0;
155out:
156 if (fd >= 0)
157 close(fd);
158 pid_iter_bpf__destroy(skel);
159 return err;
160}
161
162void delete_obj_refs_table(struct obj_refs_table *table)
163{
164 struct obj_refs *refs;
165 struct hlist_node *tmp;
166 unsigned int bkt;
167
168 hash_for_each_safe(table->table, bkt, tmp, refs, node) {
169 hash_del(&refs->node);
170 free(refs->refs);
171 free(refs);
172 }
173}
174
175void emit_obj_refs_json(struct obj_refs_table *table, __u32 id, json_writer_t *json_wtr)
176{
177 struct obj_refs *refs;
178 struct obj_ref *ref;
179 int i;
180
181 if (hash_empty(table->table))
182 return;
183
184 hash_for_each_possible(table->table, refs, node, id) {
185 if (refs->id != id)
186 continue;
187 if (refs->ref_cnt == 0)
188 break;
189
190 jsonw_name(json_wtr, "pids");
191 jsonw_start_array(json_wtr);
192 for (i = 0; i < refs->ref_cnt; i++) {
193 ref = &refs->refs[i];
194 jsonw_start_object(json_wtr);
195 jsonw_int_field(json_wtr, "pid", ref->pid);
196 jsonw_string_field(json_wtr, "comm", ref->comm);
197 jsonw_end_object(json_wtr);
198 }
199 jsonw_end_array(json_wtr);
200 break;
201 }
202}
203
204void emit_obj_refs_plain(struct obj_refs_table *table, __u32 id, const char *prefix)
205{
206 struct obj_refs *refs;
207 struct obj_ref *ref;
208 int i;
209
210 if (hash_empty(table->table))
211 return;
212
213 hash_for_each_possible(table->table, refs, node, id) {
214 if (refs->id != id)
215 continue;
216 if (refs->ref_cnt == 0)
217 break;
218
219 printf("%s", prefix);
220 for (i = 0; i < refs->ref_cnt; i++) {
221 ref = &refs->refs[i];
222 printf("%s%s(%d)", i == 0 ? "" : ", ", ref->comm, ref->pid);
223 }
224 break;
225 }
226}
227
228
229#endif
tools/bpf/bpftool/prog.c+7−152
@@ -86,158 +86,6 @@ static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) · 85 unmodified lines
86 strftime(buf, size, "%FT%T%z", &load_tm);86 strftime(buf, size, "%FT%T%z", &load_tm);
87}87}
88 88
89static int prog_fd_by_nametag(void *nametag, int **fds, bool tag)
90{
91 unsigned int id = 0;
92 int fd, nb_fds = 0;
93 void *tmp;
94 int err;
95
96 while (true) {
97 struct bpf_prog_info info = {};
98 __u32 len = sizeof(info);
99
100 err = bpf_prog_get_next_id(id, &id);
101 if (err) {
102 if (errno != ENOENT) {
103 p_err("%s", strerror(errno));
104 goto err_close_fds;
105 }
106 return nb_fds;
107 }
108
109 fd = bpf_prog_get_fd_by_id(id);
110 if (fd < 0) {
111 p_err("can't get prog by id (%u): %s",
112 id, strerror(errno));
113 goto err_close_fds;
114 }
115
116 err = bpf_obj_get_info_by_fd(fd, &info, &len);
117 if (err) {
118 p_err("can't get prog info (%u): %s",
119 id, strerror(errno));
120 goto err_close_fd;
121 }
122
123 if ((tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) ||
124 (!tag && strncmp(nametag, info.name, BPF_OBJ_NAME_LEN))) {
125 close(fd);
126 continue;
127 }
128
129 if (nb_fds > 0) {
130 tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
131 if (!tmp) {
132 p_err("failed to realloc");
133 goto err_close_fd;
134 }
135 *fds = tmp;
136 }
137 (*fds)[nb_fds++] = fd;
138 }
139
140err_close_fd:
141 close(fd);
142err_close_fds:
143 while (--nb_fds >= 0)
144 close((*fds)[nb_fds]);
145 return -1;
146}
147
148static int prog_parse_fds(int *argc, char ***argv, int **fds)
149{
150 if (is_prefix(**argv, "id")) {
151 unsigned int id;
152 char *endptr;
153
154 NEXT_ARGP();
155
156 id = strtoul(**argv, &endptr, 0);
157 if (*endptr) {
158 p_err("can't parse %s as ID", **argv);
159 return -1;
160 }
161 NEXT_ARGP();
162
163 (*fds)[0] = bpf_prog_get_fd_by_id(id);
164 if ((*fds)[0] < 0) {
165 p_err("get by id (%u): %s", id, strerror(errno));
166 return -1;
167 }
168 return 1;
169 } else if (is_prefix(**argv, "tag")) {
170 unsigned char tag[BPF_TAG_SIZE];
171
172 NEXT_ARGP();
173
174 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2,
175 tag + 3, tag + 4, tag + 5, tag + 6, tag + 7)
176 != BPF_TAG_SIZE) {
177 p_err("can't parse tag");
178 return -1;
179 }
180 NEXT_ARGP();
181
182 return prog_fd_by_nametag(tag, fds, true);
183 } else if (is_prefix(**argv, "name")) {
184 char *name;
185
186 NEXT_ARGP();
187
188 name = **argv;
189 if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
190 p_err("can't parse name");
191 return -1;
192 }
193 NEXT_ARGP();
194
195 return prog_fd_by_nametag(name, fds, false);
196 } else if (is_prefix(**argv, "pinned")) {
197 char *path;
198
199 NEXT_ARGP();
200
201 path = **argv;
202 NEXT_ARGP();
203
204 (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG);
205 if ((*fds)[0] < 0)
206 return -1;
207 return 1;
208 }
209
210 p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv);
211 return -1;
212}
213
214int prog_parse_fd(int *argc, char ***argv)
215{
216 int *fds = NULL;
217 int nb_fds, fd;
218
219 fds = malloc(sizeof(int));
220 if (!fds) {
221 p_err("mem alloc failed");
222 return -1;
223 }
224 nb_fds = prog_parse_fds(argc, argv, &fds);
225 if (nb_fds != 1) {
226 if (nb_fds > 1) {
227 p_err("several programs match this handle");
228 while (nb_fds--)
229 close(fds[nb_fds]);
230 }
231 fd = -1;
232 goto exit_free;
233 }
234
235 fd = fds[0];
236exit_free:
237 free(fds);
238 return fd;
239}
240
241static void show_prog_maps(int fd, __u32 num_maps)89static void show_prog_maps(int fd, __u32 num_maps)
242{90{
243 struct bpf_prog_info info = {};91 struct bpf_prog_info info = {};
@@ -342,6 +190,8 @@ static void print_prog_json(struct bpf_prog_info *info, int fd) · 98 unmodified lines
342 jsonw_end_array(json_wtr);190 jsonw_end_array(json_wtr);
343 }191 }
344 192
193 emit_obj_refs_json(&refs_table, info->id, json_wtr);
194
345 jsonw_end_object(json_wtr);195 jsonw_end_object(json_wtr);
346}196}
347 197
@@ -408,6 +258,8 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd) · 60 unmodified lines
408 if (info->btf_id)258 if (info->btf_id)
409 printf("\n\tbtf_id %d", info->btf_id);259 printf("\n\tbtf_id %d", info->btf_id);
410 260
261 emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");
262
411 printf("\n");263 printf("\n");
412}264}
413 265
@@ -473,6 +325,7 @@ static int do_show(int argc, char **argv) · 59 unmodified lines
473 325
474 if (show_pinned)326 if (show_pinned)
475 build_pinned_obj_table(&prog_table, BPF_OBJ_PROG);327 build_pinned_obj_table(&prog_table, BPF_OBJ_PROG);
328 build_obj_refs_table(&refs_table, BPF_OBJ_PROG);
476 329
477 if (argc == 2)330 if (argc == 2)
478 return do_show_subset(argc, argv);331 return do_show_subset(argc, argv);
@@ -514,6 +367,8 @@ static int do_show(int argc, char **argv) · 35 unmodified lines
514 if (json_output)367 if (json_output)
515 jsonw_end_array(json_wtr);368 jsonw_end_array(json_wtr);
516 369
370 delete_obj_refs_table(&refs_table);
371
517 return err;372 return err;
518}373}
519 374
tools/bpf/bpftool/skeleton/pid_iter.bpf.c+80−0
@@ -0,0 +1,80 @@
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2/* Copyright (c) 2020 Facebook */
3#include <vmlinux.h>
4#include <bpf/bpf_helpers.h>
5#include <bpf/bpf_core_read.h>
6#include <bpf/bpf_tracing.h>
7#include "pid_iter.h"
8
9/* keep in sync with the definition in main.h */
10enum bpf_obj_type {
11 BPF_OBJ_UNKNOWN,
12 BPF_OBJ_PROG,
13 BPF_OBJ_MAP,
14 BPF_OBJ_LINK,
15 BPF_OBJ_BTF,
16};
17
18extern const void bpf_link_fops __ksym;
19extern const void bpf_map_fops __ksym;
20extern const void bpf_prog_fops __ksym;
21extern const void btf_fops __ksym;
22
23const volatile enum bpf_obj_type obj_type = BPF_OBJ_UNKNOWN;
24
25static __always_inline __u32 get_obj_id(void *ent, enum bpf_obj_type type)
26{
27 switch (type) {
28 case BPF_OBJ_PROG:
29 return BPF_CORE_READ((struct bpf_prog *)ent, aux, id);
30 case BPF_OBJ_MAP:
31 return BPF_CORE_READ((struct bpf_map *)ent, id);
32 case BPF_OBJ_BTF:
33 return BPF_CORE_READ((struct btf *)ent, id);
34 case BPF_OBJ_LINK:
35 return BPF_CORE_READ((struct bpf_link *)ent, id);
36 default:
37 return 0;
38 }
39}
40
41SEC("iter/task_file")
42int iter(struct bpf_iter__task_file *ctx)
43{
44 struct file *file = ctx->file;
45 struct task_struct *task = ctx->task;
46 struct pid_iter_entry e;
47 const void *fops;
48
49 if (!file || !task)
50 return 0;
51
52 switch (obj_type) {
53 case BPF_OBJ_PROG:
54 fops = &bpf_prog_fops;
55 break;
56 case BPF_OBJ_MAP:
57 fops = &bpf_map_fops;
58 break;
59 case BPF_OBJ_BTF:
60 fops = &btf_fops;
61 break;
62 case BPF_OBJ_LINK:
63 fops = &bpf_link_fops;
64 break;
65 default:
66 return 0;
67 }
68
69 if (file->f_op != fops)
70 return 0;
71
72 e.pid = task->tgid;
73 e.id = get_obj_id(file->private_data, obj_type);
74 bpf_probe_read(&e.comm, sizeof(e.comm), task->group_leader->comm);
75 bpf_seq_write(ctx->meta->seq, &e, sizeof(e));
76
77 return 0;
78}
79
80char LICENSE[] SEC("license") = "Dual BSD/GPL";
tools/bpf/bpftool/skeleton/pid_iter.h+12−0
@@ -0,0 +1,12 @@
1/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
2/* Copyright (c) 2020 Facebook */
3#ifndef __PID_ITER_H
4#define __PID_ITER_H
5
6struct pid_iter_entry {
7 __u32 id;
8 int pid;
9 char comm[16];
10};
11
12#endif
tools/bpf/bpftool/skeleton/profiler.bpf.c+1−2
@@ -1,7 +1,6 @@
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2// Copyright (c) 2020 Facebook2// Copyright (c) 2020 Facebook
3#include "profiler.h"3#include <vmlinux.h>
4#include <linux/bpf.h>
5#include <bpf/bpf_helpers.h>4#include <bpf/bpf_helpers.h>
6#include <bpf/bpf_tracing.h>5#include <bpf/bpf_tracing.h>
7 6
tools/bpf/bpftool/skeleton/profiler.h+0−46
@@ -1,46 +0,0 @@
1/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2#ifndef __PROFILER_H
3#define __PROFILER_H
4
5/* useful typedefs from vmlinux.h */
6
7typedef signed char __s8;
8typedef unsigned char __u8;
9typedef short int __s16;
10typedef short unsigned int __u16;
11typedef int __s32;
12typedef unsigned int __u32;
13typedef long long int __s64;
14typedef long long unsigned int __u64;
15
16typedef __s8 s8;
17typedef __u8 u8;
18typedef __s16 s16;
19typedef __u16 u16;
20typedef __s32 s32;
21typedef __u32 u32;
22typedef __s64 s64;
23typedef __u64 u64;
24
25enum {
26 false = 0,
27 true = 1,
28};
29
30#ifdef __CHECKER__
31#define __bitwise__ __attribute__((bitwise))
32#else
33#define __bitwise__
34#endif
35
36typedef __u16 __bitwise__ __le16;
37typedef __u16 __bitwise__ __be16;
38typedef __u32 __bitwise__ __le32;
39typedef __u32 __bitwise__ __be32;
40typedef __u64 __bitwise__ __le64;
41typedef __u64 __bitwise__ __be64;
42
43typedef __u16 __bitwise__ __sum16;
44typedef __u32 __bitwise__ __wsum;
45
46#endif /* __PROFILER_H */
tools/build/feature/Makefile+2−2
@@ -68,7 +68,7 @@ FILES= \ · 67 unmodified lines
68 test-llvm-version.bin \68 test-llvm-version.bin \
69 test-libaio.bin \69 test-libaio.bin \
70 test-libzstd.bin \70 test-libzstd.bin \
71 test-clang-bpf-global-var.bin \71 test-clang-bpf-co-re.bin \
72 test-file-handle.bin \72 test-file-handle.bin \
73 test-libpfm4.bin73 test-libpfm4.bin
74 74
@@ -325,7 +325,7 @@ $(OUTPUT)test-libaio.bin: · 250 unmodified lines
325$(OUTPUT)test-libzstd.bin:325$(OUTPUT)test-libzstd.bin:
326 $(BUILD) -lzstd326 $(BUILD) -lzstd
327 327
328$(OUTPUT)test-clang-bpf-global-var.bin:328$(OUTPUT)test-clang-bpf-co-re.bin:
329 $(CLANG) -S -g -target bpf -o - $(patsubst %.bin,%.c,$(@F)) | \329 $(CLANG) -S -g -target bpf -o - $(patsubst %.bin,%.c,$(@F)) | \
330 grep BTF_KIND_VAR330 grep BTF_KIND_VAR
331 331
tools/build/feature/test-clang-bpf-co-re.c+9−0
@@ -0,0 +1,9 @@
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (c) 2020 Facebook
3
4struct test {
5 int a;
6 int b;
7} __attribute__((preserve_access_index));
8
9volatile struct test global_value_for_test = {};
tools/build/feature/test-clang-bpf-global-var.c+0−4
@@ -1,4 +0,0 @@
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (c) 2020 Facebook
3
4volatile int global_value_for_test = 1;
tools/lib/bpf/bpf_core_read.h+4−4
@@ -217,7 +217,7 @@ enum bpf_field_info_kind { · 216 unmodified lines
217 */217 */
218#define BPF_CORE_READ_INTO(dst, src, a, ...) \218#define BPF_CORE_READ_INTO(dst, src, a, ...) \
219 ({ \219 ({ \
220 ___core_read(bpf_core_read, dst, src, a, ##__VA_ARGS__) \220 ___core_read(bpf_core_read, dst, (src), a, ##__VA_ARGS__) \
221 })221 })
222 222
223/*223/*
@@ -227,7 +227,7 @@ enum bpf_field_info_kind { · 3 unmodified lines
227 */227 */
228#define BPF_CORE_READ_STR_INTO(dst, src, a, ...) \228#define BPF_CORE_READ_STR_INTO(dst, src, a, ...) \
229 ({ \229 ({ \
230 ___core_read(bpf_core_read_str, dst, src, a, ##__VA_ARGS__) \230 ___core_read(bpf_core_read_str, dst, (src), a, ##__VA_ARGS__)\
231 })231 })
232 232
233/*233/*
@@ -254,8 +254,8 @@ enum bpf_field_info_kind { · 20 unmodified lines
254 */254 */
255#define BPF_CORE_READ(src, a, ...) \255#define BPF_CORE_READ(src, a, ...) \
256 ({ \256 ({ \
257 ___type(src, a, ##__VA_ARGS__) __r; \257 ___type((src), a, ##__VA_ARGS__) __r; \
258 BPF_CORE_READ_INTO(&__r, src, a, ##__VA_ARGS__); \258 BPF_CORE_READ_INTO(&__r, (src), a, ##__VA_ARGS__); \
259 __r; \259 __r; \
260 })260 })
261 261
tools/lib/bpf/bpf_helpers.h+1−0
@@ -75,5 +75,6 @@ enum libbpf_tristate { · 74 unmodified lines
75};75};
76 76
77#define __kconfig __attribute__((section(".kconfig")))77#define __kconfig __attribute__((section(".kconfig")))
78#define __ksym __attribute__((section(".ksyms")))
78 79
79#endif80#endif
tools/lib/bpf/btf.h+5−0
@@ -168,6 +168,11 @@ static inline bool btf_kflag(const struct btf_type *t) · 167 unmodified lines
168 return BTF_INFO_KFLAG(t->info);168 return BTF_INFO_KFLAG(t->info);
169}169}
170 170
171static inline bool btf_is_void(const struct btf_type *t)
172{
173 return btf_kind(t) == BTF_KIND_UNKN;
174}
175
171static inline bool btf_is_int(const struct btf_type *t)176static inline bool btf_is_int(const struct btf_type *t)
172{177{
173 return btf_kind(t) == BTF_KIND_INT;178 return btf_kind(t) == BTF_KIND_INT;
tools/lib/bpf/libbpf.c+340−142
@@ -285,6 +285,7 @@ struct bpf_struct_ops { · 284 unmodified lines
285#define BSS_SEC ".bss"285#define BSS_SEC ".bss"
286#define RODATA_SEC ".rodata"286#define RODATA_SEC ".rodata"
287#define KCONFIG_SEC ".kconfig"287#define KCONFIG_SEC ".kconfig"
288#define KSYMS_SEC ".ksyms"
288#define STRUCT_OPS_SEC ".struct_ops"289#define STRUCT_OPS_SEC ".struct_ops"
289 290
290enum libbpf_map_type {291enum libbpf_map_type {
@@ -330,24 +331,39 @@ struct bpf_map { · 39 unmodified lines
330 331
331enum extern_type {332enum extern_type {
332 EXT_UNKNOWN,333 EXT_UNKNOWN,
333 EXT_CHAR,334 EXT_KCFG,
334 EXT_BOOL,335 EXT_KSYM,
335 EXT_INT,336};
336 EXT_TRISTATE,337
337 EXT_CHAR_ARR,338enum kcfg_type {
339 KCFG_UNKNOWN,
340 KCFG_CHAR,
341 KCFG_BOOL,
342 KCFG_INT,
343 KCFG_TRISTATE,
344 KCFG_CHAR_ARR,
338};345};
339 346
340struct extern_desc {347struct extern_desc {
341 const char *name;348 enum extern_type type;
342 int sym_idx;349 int sym_idx;
343 int btf_id;350 int btf_id;
344 enum extern_type type;351 int sec_btf_id;
345 int sz;352 const char *name;
346 int align;
347 int data_off;
348 bool is_signed;
349 bool is_weak;
350 bool is_set;353 bool is_set;
354 bool is_weak;
355 union {
356 struct {
357 enum kcfg_type type;
358 int sz;
359 int align;
360 int data_off;
361 bool is_signed;
362 } kcfg;
363 struct {
364 unsigned long long addr;
365 } ksym;
366 };
351};367};
352 368
353static LIST_HEAD(bpf_objects_list);369static LIST_HEAD(bpf_objects_list);
@@ -1424,19 +1440,19 @@ static struct extern_desc *find_extern_by_name(const struct bpf_object *obj, · 1070 unmodified lines
1424 return NULL;1440 return NULL;
1425}1441}
1426 1442
1427static int set_ext_value_tri(struct extern_desc *ext, void *ext_val,1443static int set_kcfg_value_tri(struct extern_desc *ext, void *ext_val,
1428 char value)1444 char value)
1429{1445{
1430 switch (ext->type) {1446 switch (ext->kcfg.type) {
1431 case EXT_BOOL:1447 case KCFG_BOOL:
1432 if (value == 'm') {1448 if (value == 'm') {
1433 pr_warn("extern %s=%c should be tristate or char\n",1449 pr_warn("extern (kcfg) %s=%c should be tristate or char\n",
1434 ext->name, value);1450 ext->name, value);
1435 return -EINVAL;1451 return -EINVAL;
1436 }1452 }
1437 *(bool *)ext_val = value == 'y' ? true : false;1453 *(bool *)ext_val = value == 'y' ? true : false;
1438 break;1454 break;
1439 case EXT_TRISTATE:1455 case KCFG_TRISTATE:
1440 if (value == 'y')1456 if (value == 'y')
1441 *(enum libbpf_tristate *)ext_val = TRI_YES;1457 *(enum libbpf_tristate *)ext_val = TRI_YES;
1442 else if (value == 'm')1458 else if (value == 'm')
@@ -1444,14 +1460,14 @@ static int set_ext_value_tri(struct extern_desc *ext, void *ext_val, · 1 unmodified line
1444 else /* value == 'n' */1460 else /* value == 'n' */
1445 *(enum libbpf_tristate *)ext_val = TRI_NO;1461 *(enum libbpf_tristate *)ext_val = TRI_NO;
1446 break;1462 break;
1447 case EXT_CHAR:1463 case KCFG_CHAR:
1448 *(char *)ext_val = value;1464 *(char *)ext_val = value;
1449 break;1465 break;
1450 case EXT_UNKNOWN:1466 case KCFG_UNKNOWN:
1451 case EXT_INT:1467 case KCFG_INT:
1452 case EXT_CHAR_ARR:1468 case KCFG_CHAR_ARR:
1453 default:1469 default:
1454 pr_warn("extern %s=%c should be bool, tristate, or char\n",1470 pr_warn("extern (kcfg) %s=%c should be bool, tristate, or char\n",
1455 ext->name, value);1471 ext->name, value);
1456 return -EINVAL;1472 return -EINVAL;
1457 }1473 }
@@ -1459,29 +1475,29 @@ static int set_ext_value_tri(struct extern_desc *ext, void *ext_val, · 1 unmodified line
1459 return 0;1475 return 0;
1460}1476}
1461 1477
1462static int set_ext_value_str(struct extern_desc *ext, char *ext_val,1478static int set_kcfg_value_str(struct extern_desc *ext, char *ext_val,
1463 const char *value)1479 const char *value)
1464{1480{
1465 size_t len;1481 size_t len;
1466 1482
1467 if (ext->type != EXT_CHAR_ARR) {1483 if (ext->kcfg.type != KCFG_CHAR_ARR) {
1468 pr_warn("extern %s=%s should char array\n", ext->name, value);1484 pr_warn("extern (kcfg) %s=%s should be char array\n", ext->name, value);
1469 return -EINVAL;1485 return -EINVAL;
1470 }1486 }
1471 1487
1472 len = strlen(value);1488 len = strlen(value);
1473 if (value[len - 1] != '"') {1489 if (value[len - 1] != '"') {
1474 pr_warn("extern '%s': invalid string config '%s'\n",1490 pr_warn("extern (kcfg) '%s': invalid string config '%s'\n",
1475 ext->name, value);1491 ext->name, value);
1476 return -EINVAL;1492 return -EINVAL;
1477 }1493 }
1478 1494
1479 /* strip quotes */1495 /* strip quotes */
1480 len -= 2;1496 len -= 2;
1481 if (len >= ext->sz) {1497 if (len >= ext->kcfg.sz) {
1482 pr_warn("extern '%s': long string config %s of (%zu bytes) truncated to %d bytes\n",1498 pr_warn("extern (kcfg) '%s': long string config %s of (%zu bytes) truncated to %d bytes\n",
1483 ext->name, value, len, ext->sz - 1);1499 ext->name, value, len, ext->kcfg.sz - 1);
1484 len = ext->sz - 1;1500 len = ext->kcfg.sz - 1;
1485 }1501 }
1486 memcpy(ext_val, value + 1, len);1502 memcpy(ext_val, value + 1, len);
1487 ext_val[len] = '\0';1503 ext_val[len] = '\0';
@@ -1508,11 +1524,11 @@ static int parse_u64(const char *value, __u64 *res) · 20 unmodified lines
1508 return 0;1524 return 0;
1509}1525}
1510 1526
1511static bool is_ext_value_in_range(const struct extern_desc *ext, __u64 v)1527static bool is_kcfg_value_in_range(const struct extern_desc *ext, __u64 v)
1512{1528{
1513 int bit_sz = ext->sz * 8;1529 int bit_sz = ext->kcfg.sz * 8;
1514 1530
1515 if (ext->sz == 8)1531 if (ext->kcfg.sz == 8)
1516 return true;1532 return true;
1517 1533
1518 /* Validate that value stored in u64 fits in integer of `ext->sz`1534 /* Validate that value stored in u64 fits in integer of `ext->sz`
@@ -1527,26 +1543,26 @@ static bool is_ext_value_in_range(const struct extern_desc *ext, __u64 v) · 8 unmodified lines
1527 * For unsigned target integer, check that all the (64 - Y) bits are1543 * For unsigned target integer, check that all the (64 - Y) bits are
1528 * zero.1544 * zero.
1529 */1545 */
1530 if (ext->is_signed)1546 if (ext->kcfg.is_signed)
1531 return v + (1ULL << (bit_sz - 1)) < (1ULL << bit_sz);1547 return v + (1ULL << (bit_sz - 1)) < (1ULL << bit_sz);
1532 else1548 else
1533 return (v >> bit_sz) == 0;1549 return (v >> bit_sz) == 0;
1534}1550}
1535 1551
1536static int set_ext_value_num(struct extern_desc *ext, void *ext_val,1552static int set_kcfg_value_num(struct extern_desc *ext, void *ext_val,
1537 __u64 value)1553 __u64 value)
1538{1554{
1539 if (ext->type != EXT_INT && ext->type != EXT_CHAR) {1555 if (ext->kcfg.type != KCFG_INT && ext->kcfg.type != KCFG_CHAR) {
1540 pr_warn("extern %s=%llu should be integer\n",1556 pr_warn("extern (kcfg) %s=%llu should be integer\n",
1541 ext->name, (unsigned long long)value);1557 ext->name, (unsigned long long)value);
1542 return -EINVAL;1558 return -EINVAL;
1543 }1559 }
1544 if (!is_ext_value_in_range(ext, value)) {1560 if (!is_kcfg_value_in_range(ext, value)) {
1545 pr_warn("extern %s=%llu value doesn't fit in %d bytes\n",1561 pr_warn("extern (kcfg) %s=%llu value doesn't fit in %d bytes\n",
1546 ext->name, (unsigned long long)value, ext->sz);1562 ext->name, (unsigned long long)value, ext->kcfg.sz);
1547 return -ERANGE;1563 return -ERANGE;
1548 }1564 }
1549 switch (ext->sz) {1565 switch (ext->kcfg.sz) {
1550 case 1: *(__u8 *)ext_val = value; break;1566 case 1: *(__u8 *)ext_val = value; break;
1551 case 2: *(__u16 *)ext_val = value; break;1567 case 2: *(__u16 *)ext_val = value; break;
1552 case 4: *(__u32 *)ext_val = value; break;1568 case 4: *(__u32 *)ext_val = value; break;
@@ -1592,30 +1608,30 @@ static int bpf_object__process_kconfig_line(struct bpf_object *obj, · 39 unmodified lines
1592 if (!ext || ext->is_set)1608 if (!ext || ext->is_set)
1593 return 0;1609 return 0;
1594 1610
1595 ext_val = data + ext->data_off;1611 ext_val = data + ext->kcfg.data_off;
1596 value = sep + 1;1612 value = sep + 1;
1597 1613
1598 switch (*value) {1614 switch (*value) {
1599 case 'y': case 'n': case 'm':1615 case 'y': case 'n': case 'm':
1600 err = set_ext_value_tri(ext, ext_val, *value);1616 err = set_kcfg_value_tri(ext, ext_val, *value);
1601 break;1617 break;
1602 case '"':1618 case '"':
1603 err = set_ext_value_str(ext, ext_val, value);1619 err = set_kcfg_value_str(ext, ext_val, value);
1604 break;1620 break;
1605 default:1621 default:
1606 /* assume integer */1622 /* assume integer */
1607 err = parse_u64(value, &num);1623 err = parse_u64(value, &num);
1608 if (err) {1624 if (err) {
1609 pr_warn("extern %s=%s should be integer\n",1625 pr_warn("extern (kcfg) %s=%s should be integer\n",
1610 ext->name, value);1626 ext->name, value);
1611 return err;1627 return err;
1612 }1628 }
1613 err = set_ext_value_num(ext, ext_val, num);1629 err = set_kcfg_value_num(ext, ext_val, num);
1614 break;1630 break;
1615 }1631 }
1616 if (err)1632 if (err)
1617 return err;1633 return err;
1618 pr_debug("extern %s=%s\n", ext->name, value);1634 pr_debug("extern (kcfg) %s=%s\n", ext->name, value);
1619 return 0;1635 return 0;
1620}1636}
1621 1637
@@ -1686,16 +1702,20 @@ static int bpf_object__read_kconfig_mem(struct bpf_object *obj, · 64 unmodified lines
1686 1702
1687static int bpf_object__init_kconfig_map(struct bpf_object *obj)1703static int bpf_object__init_kconfig_map(struct bpf_object *obj)
1688{1704{
1689 struct extern_desc *last_ext;1705 struct extern_desc *last_ext = NULL, *ext;
1690 size_t map_sz;1706 size_t map_sz;
1691 int err;1707 int i, err;
1692 1708
1693 if (obj->nr_extern == 0)1709 for (i = 0; i < obj->nr_extern; i++) {
1694 return 0;1710 ext = &obj->externs[i];
1711 if (ext->type == EXT_KCFG)
1712 last_ext = ext;
1713 }
1695 1714
1696 last_ext = &obj->externs[obj->nr_extern - 1];1715 if (!last_ext)
1697 map_sz = last_ext->data_off + last_ext->sz;1716 return 0;
1698 1717
1718 map_sz = last_ext->kcfg.data_off + last_ext->kcfg.sz;
1699 err = bpf_object__init_internal_map(obj, LIBBPF_MAP_KCONFIG,1719 err = bpf_object__init_internal_map(obj, LIBBPF_MAP_KCONFIG,
1700 obj->efile.symbols_shndx,1720 obj->efile.symbols_shndx,
1701 NULL, map_sz);1721 NULL, map_sz);
@@ -2714,8 +2734,33 @@ static int find_extern_btf_id(const struct btf *btf, const char *ext_name) · 1012 unmodified lines
2714 return -ENOENT;2734 return -ENOENT;
2715}2735}
2716 2736
2717static enum extern_type find_extern_type(const struct btf *btf, int id,2737static int find_extern_sec_btf_id(struct btf *btf, int ext_btf_id) {
2718 bool *is_signed)2738 const struct btf_var_secinfo *vs;
2739 const struct btf_type *t;
2740 int i, j, n;
2741
2742 if (!btf)
2743 return -ESRCH;
2744
2745 n = btf__get_nr_types(btf);
2746 for (i = 1; i <= n; i++) {
2747 t = btf__type_by_id(btf, i);
2748
2749 if (!btf_is_datasec(t))
2750 continue;
2751
2752 vs = btf_var_secinfos(t);
2753 for (j = 0; j < btf_vlen(t); j++, vs++) {
2754 if (vs->type == ext_btf_id)
2755 return i;
2756 }
2757 }
2758
2759 return -ENOENT;
2760}
2761
2762static enum kcfg_type find_kcfg_type(const struct btf *btf, int id,
2763 bool *is_signed)
2719{2764{
2720 const struct btf_type *t;2765 const struct btf_type *t;
2721 const char *name;2766 const char *name;
@@ -2730,29 +2775,29 @@ static enum extern_type find_extern_type(const struct btf *btf, int id, · 8 unmodified lines
2730 int enc = btf_int_encoding(t);2775 int enc = btf_int_encoding(t);
2731 2776
2732 if (enc & BTF_INT_BOOL)2777 if (enc & BTF_INT_BOOL)
2733 return t->size == 1 ? EXT_BOOL : EXT_UNKNOWN;2778 return t->size == 1 ? KCFG_BOOL : KCFG_UNKNOWN;
2734 if (is_signed)2779 if (is_signed)
2735 *is_signed = enc & BTF_INT_SIGNED;2780 *is_signed = enc & BTF_INT_SIGNED;
2736 if (t->size == 1)2781 if (t->size == 1)
2737 return EXT_CHAR;2782 return KCFG_CHAR;
2738 if (t->size < 1 || t->size > 8 || (t->size & (t->size - 1)))2783 if (t->size < 1 || t->size > 8 || (t->size & (t->size - 1)))
2739 return EXT_UNKNOWN;2784 return KCFG_UNKNOWN;
2740 return EXT_INT;2785 return KCFG_INT;
2741 }2786 }
2742 case BTF_KIND_ENUM:2787 case BTF_KIND_ENUM:
2743 if (t->size != 4)2788 if (t->size != 4)
2744 return EXT_UNKNOWN;2789 return KCFG_UNKNOWN;
2745 if (strcmp(name, "libbpf_tristate"))2790 if (strcmp(name, "libbpf_tristate"))
2746 return EXT_UNKNOWN;2791 return KCFG_UNKNOWN;
2747 return EXT_TRISTATE;2792 return KCFG_TRISTATE;
2748 case BTF_KIND_ARRAY:2793 case BTF_KIND_ARRAY:
2749 if (btf_array(t)->nelems == 0)2794 if (btf_array(t)->nelems == 0)
2750 return EXT_UNKNOWN;2795 return KCFG_UNKNOWN;
2751 if (find_extern_type(btf, btf_array(t)->type, NULL) != EXT_CHAR)2796 if (find_kcfg_type(btf, btf_array(t)->type, NULL) != KCFG_CHAR)
2752 return EXT_UNKNOWN;2797 return KCFG_UNKNOWN;
2753 return EXT_CHAR_ARR;2798 return KCFG_CHAR_ARR;
2754 default:2799 default:
2755 return EXT_UNKNOWN;2800 return KCFG_UNKNOWN;
2756 }2801 }
2757}2802}
2758 2803
@@ -2761,23 +2806,45 @@ static int cmp_externs(const void *_a, const void *_b) · 2 unmodified lines
2761 const struct extern_desc *a = _a;2806 const struct extern_desc *a = _a;
2762 const struct extern_desc *b = _b;2807 const struct extern_desc *b = _b;
2763 2808
2764 /* descending order by alignment requirements */2809 if (a->type != b->type)
2765 if (a->align != b->align)2810 return a->type < b->type ? -1 : 1;
2766 return a->align > b->align ? -1 : 1;2811
2767 /* ascending order by size, within same alignment class */2812 if (a->type == EXT_KCFG) {
2768 if (a->sz != b->sz)2813 /* descending order by alignment requirements */
2769 return a->sz < b->sz ? -1 : 1;2814 if (a->kcfg.align != b->kcfg.align)
2815 return a->kcfg.align > b->kcfg.align ? -1 : 1;
2816 /* ascending order by size, within same alignment class */
2817 if (a->kcfg.sz != b->kcfg.sz)
2818 return a->kcfg.sz < b->kcfg.sz ? -1 : 1;
2819 }
2820
2770 /* resolve ties by name */2821 /* resolve ties by name */
2771 return strcmp(a->name, b->name);2822 return strcmp(a->name, b->name);
2772}2823}
2773 2824
2825static int find_int_btf_id(const struct btf *btf)
2826{
2827 const struct btf_type *t;
2828 int i, n;
2829
2830 n = btf__get_nr_types(btf);
2831 for (i = 1; i <= n; i++) {
2832 t = btf__type_by_id(btf, i);
2833
2834 if (btf_is_int(t) && btf_int_bits(t) == 32)
2835 return i;
2836 }
2837
2838 return 0;
2839}
2840
2774static int bpf_object__collect_externs(struct bpf_object *obj)2841static int bpf_object__collect_externs(struct bpf_object *obj)
2775{2842{
2843 struct btf_type *sec, *kcfg_sec = NULL, *ksym_sec = NULL;
2776 const struct btf_type *t;2844 const struct btf_type *t;
2777 struct extern_desc *ext;2845 struct extern_desc *ext;
2778 int i, n, off, btf_id;2846 int i, n, off;
2779 struct btf_type *sec;2847 const char *ext_name, *sec_name;
2780 const char *ext_name;
2781 Elf_Scn *scn;2848 Elf_Scn *scn;
2782 GElf_Shdr sh;2849 GElf_Shdr sh;
2783 2850
@@ -2823,22 +2890,50 @@ static int bpf_object__collect_externs(struct bpf_object *obj) · 39 unmodified lines
2823 ext->name = btf__name_by_offset(obj->btf, t->name_off);2890 ext->name = btf__name_by_offset(obj->btf, t->name_off);
2824 ext->sym_idx = i;2891 ext->sym_idx = i;
2825 ext->is_weak = GELF_ST_BIND(sym.st_info) == STB_WEAK;2892 ext->is_weak = GELF_ST_BIND(sym.st_info) == STB_WEAK;
2826 ext->sz = btf__resolve_size(obj->btf, t->type);2893
2827 if (ext->sz <= 0) {2894 ext->sec_btf_id = find_extern_sec_btf_id(obj->btf, ext->btf_id);
2828 pr_warn("failed to resolve size of extern '%s': %d\n",2895 if (ext->sec_btf_id <= 0) {
2829 ext_name, ext->sz);2896 pr_warn("failed to find BTF for extern '%s' [%d] section: %d\n",
2830 return ext->sz;2897 ext_name, ext->btf_id, ext->sec_btf_id);
2831 }2898 return ext->sec_btf_id;
2832 ext->align = btf__align_of(obj->btf, t->type);2899 }
2833 if (ext->align <= 0) {2900 sec = (void *)btf__type_by_id(obj->btf, ext->sec_btf_id);
2834 pr_warn("failed to determine alignment of extern '%s': %d\n",2901 sec_name = btf__name_by_offset(obj->btf, sec->name_off);
2835 ext_name, ext->align);2902
2836 return -EINVAL;2903 if (strcmp(sec_name, KCONFIG_SEC) == 0) {
2837 }2904 kcfg_sec = sec;
2838 ext->type = find_extern_type(obj->btf, t->type,2905 ext->type = EXT_KCFG;
2839 &ext->is_signed);2906 ext->kcfg.sz = btf__resolve_size(obj->btf, t->type);
2840 if (ext->type == EXT_UNKNOWN) {2907 if (ext->kcfg.sz <= 0) {
2841 pr_warn("extern '%s' type is unsupported\n", ext_name);2908 pr_warn("failed to resolve size of extern (kcfg) '%s': %d\n",
2909 ext_name, ext->kcfg.sz);
2910 return ext->kcfg.sz;
2911 }
2912 ext->kcfg.align = btf__align_of(obj->btf, t->type);
2913 if (ext->kcfg.align <= 0) {
2914 pr_warn("failed to determine alignment of extern (kcfg) '%s': %d\n",
2915 ext_name, ext->kcfg.align);
2916 return -EINVAL;
2917 }
2918 ext->kcfg.type = find_kcfg_type(obj->btf, t->type,
2919 &ext->kcfg.is_signed);
2920 if (ext->kcfg.type == KCFG_UNKNOWN) {
2921 pr_warn("extern (kcfg) '%s' type is unsupported\n", ext_name);
2922 return -ENOTSUP;
2923 }
2924 } else if (strcmp(sec_name, KSYMS_SEC) == 0) {
2925 const struct btf_type *vt;
2926
2927 ksym_sec = sec;
2928 ext->type = EXT_KSYM;
2929
2930 vt = skip_mods_and_typedefs(obj->btf, t->type, NULL);
2931 if (!btf_is_void(vt)) {
2932 pr_warn("extern (ksym) '%s' is not typeless (void)\n", ext_name);
2933 return -ENOTSUP;
2934 }
2935 } else {
2936 pr_warn("unrecognized extern section '%s'\n", sec_name);
2842 return -ENOTSUP;2937 return -ENOTSUP;
2843 }2938 }
2844 }2939 }
@@ -2847,42 +2942,80 @@ static int bpf_object__collect_externs(struct bpf_object *obj) · 2 unmodified lines
2847 if (!obj->nr_extern)2942 if (!obj->nr_extern)
2848 return 0;2943 return 0;
2849 2944
2850 /* sort externs by (alignment, size, name) and calculate their offsets2945 /* sort externs by type, for kcfg ones also by (align, size, name) */
2851 * within a map */
2852 qsort(obj->externs, obj->nr_extern, sizeof(*ext), cmp_externs);2946 qsort(obj->externs, obj->nr_extern, sizeof(*ext), cmp_externs);
2853 off = 0;
2854 for (i = 0; i < obj->nr_extern; i++) {
2855 ext = &obj->externs[i];
2856 ext->data_off = roundup(off, ext->align);
2857 off = ext->data_off + ext->sz;
2858 pr_debug("extern #%d: symbol %d, off %u, name %s\n",
2859 i, ext->sym_idx, ext->data_off, ext->name);
2860 }
2861 2947
2862 btf_id = btf__find_by_name(obj->btf, KCONFIG_SEC);2948 /* for .ksyms section, we need to turn all externs into allocated
2863 if (btf_id <= 0) {2949 * variables in BTF to pass kernel verification; we do this by
2864 pr_warn("no BTF info found for '%s' datasec\n", KCONFIG_SEC);2950 * pretending that each extern is a 8-byte variable
2865 return -ESRCH;2951 */
2866 }2952 if (ksym_sec) {
2953 /* find existing 4-byte integer type in BTF to use for fake
2954 * extern variables in DATASEC
2955 */
2956 int int_btf_id = find_int_btf_id(obj->btf);
2867 2957
2868 sec = (struct btf_type *)btf__type_by_id(obj->btf, btf_id);2958 for (i = 0; i < obj->nr_extern; i++) {
2869 sec->size = off;2959 ext = &obj->externs[i];
2870 n = btf_vlen(sec);2960 if (ext->type != EXT_KSYM)
2871 for (i = 0; i < n; i++) {2961 continue;
2872 struct btf_var_secinfo *vs = btf_var_secinfos(sec) + i;2962 pr_debug("extern (ksym) #%d: symbol %d, name %s\n",
2873 2963 i, ext->sym_idx, ext->name);
2874 t = btf__type_by_id(obj->btf, vs->type);2964 }
2875 ext_name = btf__name_by_offset(obj->btf, t->name_off);2965
2876 ext = find_extern_by_name(obj, ext_name);2966 sec = ksym_sec;
2877 if (!ext) {2967 n = btf_vlen(sec);
2878 pr_warn("failed to find extern definition for BTF var '%s'\n",2968 for (i = 0, off = 0; i < n; i++, off += sizeof(int)) {
2879 ext_name);2969 struct btf_var_secinfo *vs = btf_var_secinfos(sec) + i;
2880 return -ESRCH;2970 struct btf_type *vt;
2971
2972 vt = (void *)btf__type_by_id(obj->btf, vs->type);
2973 ext_name = btf__name_by_offset(obj->btf, vt->name_off);
2974 ext = find_extern_by_name(obj, ext_name);
2975 if (!ext) {
2976 pr_warn("failed to find extern definition for BTF var '%s'\n",
2977 ext_name);
2978 return -ESRCH;
2979 }
2980 btf_var(vt)->linkage = BTF_VAR_GLOBAL_ALLOCATED;
2981 vt->type = int_btf_id;
2982 vs->offset = off;
2983 vs->size = sizeof(int);
2881 }2984 }
2882 vs->offset = ext->data_off;2985 sec->size = off;
2883 btf_var(t)->linkage = BTF_VAR_GLOBAL_ALLOCATED;
2884 }2986 }
2885 2987
2988 if (kcfg_sec) {
2989 sec = kcfg_sec;
2990 /* for kcfg externs calculate their offsets within a .kconfig map */
2991 off = 0;
2992 for (i = 0; i < obj->nr_extern; i++) {
2993 ext = &obj->externs[i];
2994 if (ext->type != EXT_KCFG)
2995 continue;
2996
2997 ext->kcfg.data_off = roundup(off, ext->kcfg.align);
2998 off = ext->kcfg.data_off + ext->kcfg.sz;
2999 pr_debug("extern (kcfg) #%d: symbol %d, off %u, name %s\n",
3000 i, ext->sym_idx, ext->kcfg.data_off, ext->name);
3001 }
3002 sec->size = off;
3003 n = btf_vlen(sec);
3004 for (i = 0; i < n; i++) {
3005 struct btf_var_secinfo *vs = btf_var_secinfos(sec) + i;
3006
3007 t = btf__type_by_id(obj->btf, vs->type);
3008 ext_name = btf__name_by_offset(obj->btf, t->name_off);
3009 ext = find_extern_by_name(obj, ext_name);
3010 if (!ext) {
3011 pr_warn("failed to find extern definition for BTF var '%s'\n",
3012 ext_name);
3013 return -ESRCH;
3014 }
3015 btf_var(t)->linkage = BTF_VAR_GLOBAL_ALLOCATED;
3016 vs->offset = ext->kcfg.data_off;
3017 }
3018 }
2886 return 0;3019 return 0;
2887}3020}
2888 3021
@@ -3012,11 +3145,11 @@ static int bpf_program__record_reloc(struct bpf_program *prog, · 123 unmodified lines
3012 sym_idx);3145 sym_idx);
3013 return -LIBBPF_ERRNO__RELOC;3146 return -LIBBPF_ERRNO__RELOC;
3014 }3147 }
3015 pr_debug("found extern #%d '%s' (sym %d, off %u) for insn %u\n",3148 pr_debug("found extern #%d '%s' (sym %d) for insn %u\n",
3016 i, ext->name, ext->sym_idx, ext->data_off, insn_idx);3149 i, ext->name, ext->sym_idx, insn_idx);
3017 reloc_desc->type = RELO_EXTERN;3150 reloc_desc->type = RELO_EXTERN;
3018 reloc_desc->insn_idx = insn_idx;3151 reloc_desc->insn_idx = insn_idx;
3019 reloc_desc->sym_off = ext->data_off;3152 reloc_desc->sym_off = i; /* sym_off stores extern index */
3020 return 0;3153 return 0;
3021 }3154 }
3022 3155
@@ -4941,6 +5074,7 @@ bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj) · 1918 unmodified lines
4941 for (i = 0; i < prog->nr_reloc; i++) {5074 for (i = 0; i < prog->nr_reloc; i++) {
4942 struct reloc_desc *relo = &prog->reloc_desc[i];5075 struct reloc_desc *relo = &prog->reloc_desc[i];
4943 struct bpf_insn *insn = &prog->insns[relo->insn_idx];5076 struct bpf_insn *insn = &prog->insns[relo->insn_idx];
5077 struct extern_desc *ext;
4944 5078
4945 if (relo->insn_idx + 1 >= (int)prog->insns_cnt) {5079 if (relo->insn_idx + 1 >= (int)prog->insns_cnt) {
4946 pr_warn("relocation out of range: '%s'\n",5080 pr_warn("relocation out of range: '%s'\n",
@@ -4959,9 +5093,15 @@ bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj) · 12 unmodified lines
4959 insn[0].imm = obj->maps[relo->map_idx].fd;5093 insn[0].imm = obj->maps[relo->map_idx].fd;
4960 break;5094 break;
4961 case RELO_EXTERN:5095 case RELO_EXTERN:
4962 insn[0].src_reg = BPF_PSEUDO_MAP_VALUE;5096 ext = &obj->externs[relo->sym_off];
4963 insn[0].imm = obj->maps[obj->kconfig_map_idx].fd;5097 if (ext->type == EXT_KCFG) {
4964 insn[1].imm = relo->sym_off;5098 insn[0].src_reg = BPF_PSEUDO_MAP_VALUE;
5099 insn[0].imm = obj->maps[obj->kconfig_map_idx].fd;
5100 insn[1].imm = ext->kcfg.data_off;
5101 } else /* EXT_KSYM */ {
5102 insn[0].imm = (__u32)ext->ksym.addr;
5103 insn[1].imm = ext->ksym.addr >> 32;
5104 }
4965 break;5105 break;
4966 case RELO_CALL:5106 case RELO_CALL:
4967 err = bpf_program__reloc_text(prog, obj, relo);5107 err = bpf_program__reloc_text(prog, obj, relo);
@@ -5580,56 +5720,114 @@ static int bpf_object__sanitize_maps(struct bpf_object *obj) · 612 unmodified lines
5580 return 0;5720 return 0;
5581}5721}
5582 5722
5723static int bpf_object__read_kallsyms_file(struct bpf_object *obj)
5724{
5725 char sym_type, sym_name[500];
5726 unsigned long long sym_addr;
5727 struct extern_desc *ext;
5728 int ret, err = 0;
5729 FILE *f;
5730
5731 f = fopen("/proc/kallsyms", "r");
5732 if (!f) {
5733 err = -errno;
5734 pr_warn("failed to open /proc/kallsyms: %d\n", err);
5735 return err;
5736 }
5737
5738 while (true) {
5739 ret = fscanf(f, "%llx %c %499s%*[^\n]\n",
5740 &sym_addr, &sym_type, sym_name);
5741 if (ret == EOF && feof(f))
5742 break;
5743 if (ret != 3) {
5744 pr_warn("failed to read kallasyms entry: %d\n", ret);
5745 err = -EINVAL;
5746 goto out;
5747 }
5748
5749 ext = find_extern_by_name(obj, sym_name);
5750 if (!ext || ext->type != EXT_KSYM)
5751 continue;
5752
5753 if (ext->is_set && ext->ksym.addr != sym_addr) {
5754 pr_warn("extern (ksym) '%s' resolution is ambiguous: 0x%llx or 0x%llx\n",
5755 sym_name, ext->ksym.addr, sym_addr);
5756 err = -EINVAL;
5757 goto out;
5758 }
5759 if (!ext->is_set) {
5760 ext->is_set = true;
5761 ext->ksym.addr = sym_addr;
5762 pr_debug("extern (ksym) %s=0x%llx\n", sym_name, sym_addr);
5763 }
5764 }
5765
5766out:
5767 fclose(f);
5768 return err;
5769}
5770
5583static int bpf_object__resolve_externs(struct bpf_object *obj,5771static int bpf_object__resolve_externs(struct bpf_object *obj,
5584 const char *extra_kconfig)5772 const char *extra_kconfig)
5585{5773{
5586 bool need_config = false;5774 bool need_config = false, need_kallsyms = false;
5587 struct extern_desc *ext;5775 struct extern_desc *ext;
5776 void *kcfg_data = NULL;
5588 int err, i;5777 int err, i;
5589 void *data;
5590 5778
5591 if (obj->nr_extern == 0)5779 if (obj->nr_extern == 0)
5592 return 0;5780 return 0;
5593 5781
5594 data = obj->maps[obj->kconfig_map_idx].mmaped;5782 if (obj->kconfig_map_idx >= 0)
5783 kcfg_data = obj->maps[obj->kconfig_map_idx].mmaped;
5595 5784
5596 for (i = 0; i < obj->nr_extern; i++) {5785 for (i = 0; i < obj->nr_extern; i++) {
5597 ext = &obj->externs[i];5786 ext = &obj->externs[i];
5598 5787
5599 if (strcmp(ext->name, "LINUX_KERNEL_VERSION") == 0) {5788 if (ext->type == EXT_KCFG &&
5600 void *ext_val = data + ext->data_off;5789 strcmp(ext->name, "LINUX_KERNEL_VERSION") == 0) {
5790 void *ext_val = kcfg_data + ext->kcfg.data_off;
5601 __u32 kver = get_kernel_version();5791 __u32 kver = get_kernel_version();
5602 5792
5603 if (!kver) {5793 if (!kver) {
5604 pr_warn("failed to get kernel version\n");5794 pr_warn("failed to get kernel version\n");
5605 return -EINVAL;5795 return -EINVAL;
5606 }5796 }
5607 err = set_ext_value_num(ext, ext_val, kver);5797 err = set_kcfg_value_num(ext, ext_val, kver);
5608 if (err)5798 if (err)
5609 return err;5799 return err;
5610 pr_debug("extern %s=0x%x\n", ext->name, kver);5800 pr_debug("extern (kcfg) %s=0x%x\n", ext->name, kver);
5611 } else if (strncmp(ext->name, "CONFIG_", 7) == 0) {5801 } else if (ext->type == EXT_KCFG &&
5802 strncmp(ext->name, "CONFIG_", 7) == 0) {
5612 need_config = true;5803 need_config = true;
5804 } else if (ext->type == EXT_KSYM) {
5805 need_kallsyms = true;
5613 } else {5806 } else {
5614 pr_warn("unrecognized extern '%s'\n", ext->name);5807 pr_warn("unrecognized extern '%s'\n", ext->name);
5615 return -EINVAL;5808 return -EINVAL;
5616 }5809 }
5617 }5810 }
5618 if (need_config && extra_kconfig) {5811 if (need_config && extra_kconfig) {
5619 err = bpf_object__read_kconfig_mem(obj, extra_kconfig, data);5812 err = bpf_object__read_kconfig_mem(obj, extra_kconfig, kcfg_data);
5620 if (err)5813 if (err)
5621 return -EINVAL;5814 return -EINVAL;
5622 need_config = false;5815 need_config = false;
5623 for (i = 0; i < obj->nr_extern; i++) {5816 for (i = 0; i < obj->nr_extern; i++) {
5624 ext = &obj->externs[i];5817 ext = &obj->externs[i];
5625 if (!ext->is_set) {5818 if (ext->type == EXT_KCFG && !ext->is_set) {
5626 need_config = true;5819 need_config = true;
5627 break;5820 break;
5628 }5821 }
5629 }5822 }
5630 }5823 }
5631 if (need_config) {5824 if (need_config) {
5632 err = bpf_object__read_kconfig_file(obj, data);5825 err = bpf_object__read_kconfig_file(obj, kcfg_data);
5826 if (err)
5827 return -EINVAL;
5828 }
5829 if (need_kallsyms) {
5830 err = bpf_object__read_kallsyms_file(obj);
5633 if (err)5831 if (err)
5634 return -EINVAL;5832 return -EINVAL;
5635 }5833 }
tools/testing/selftests/bpf/prog_tests/ksyms.c+71−0
@@ -0,0 +1,71 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2019 Facebook */
3
4#include <test_progs.h>
5#include "test_ksyms.skel.h"
6#include <sys/stat.h>
7
8static int duration;
9
10static __u64 kallsyms_find(const char *sym)
11{
12 char type, name[500];
13 __u64 addr, res = 0;
14 FILE *f;
15
16 f = fopen("/proc/kallsyms", "r");
17 if (CHECK(!f, "kallsyms_fopen", "failed to open: %d\n", errno))
18 return 0;
19
20 while (fscanf(f, "%llx %c %499s%*[^\n]\n", &addr, &type, name) > 0) {
21 if (strcmp(name, sym) == 0) {
22 res = addr;
23 goto out;
24 }
25 }
26
27 CHECK(false, "not_found", "symbol %s not found\n", sym);
28out:
29 fclose(f);
30 return res;
31}
32
33void test_ksyms(void)
34{
35 __u64 link_fops_addr = kallsyms_find("bpf_link_fops");
36 const char *btf_path = "/sys/kernel/btf/vmlinux";
37 struct test_ksyms *skel;
38 struct test_ksyms__data *data;
39 struct stat st;
40 __u64 btf_size;
41 int err;
42
43 if (CHECK(stat(btf_path, &st), "stat_btf", "err %d\n", errno))
44 return;
45 btf_size = st.st_size;
46
47 skel = test_ksyms__open_and_load();
48 if (CHECK(!skel, "skel_open", "failed to open and load skeleton\n"))
49 return;
50
51 err = test_ksyms__attach(skel);
52 if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err))
53 goto cleanup;
54
55 /* trigger tracepoint */
56 usleep(1);
57
58 data = skel->data;
59 CHECK(data->out__bpf_link_fops != link_fops_addr, "bpf_link_fops",
60 "got 0x%llx, exp 0x%llx\n",
61 data->out__bpf_link_fops, link_fops_addr);
62 CHECK(data->out__bpf_link_fops1 != 0, "bpf_link_fops1",
63 "got %llu, exp %llu\n", data->out__bpf_link_fops1, (__u64)0);
64 CHECK(data->out__btf_size != btf_size, "btf_size",
65 "got %llu, exp %llu\n", data->out__btf_size, btf_size);
66 CHECK(data->out__per_cpu_start != 0, "__per_cpu_start",
67 "got %llu, exp %llu\n", data->out__per_cpu_start, (__u64)0);
68
69cleanup:
70 test_ksyms__destroy(skel);
71}
tools/testing/selftests/bpf/progs/test_ksyms.c+32−0
@@ -0,0 +1,32 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2019 Facebook */
3
4#include <stdbool.h>
5#include <linux/bpf.h>
6#include <bpf/bpf_helpers.h>
7
8__u64 out__bpf_link_fops = -1;
9__u64 out__bpf_link_fops1 = -1;
10__u64 out__btf_size = -1;
11__u64 out__per_cpu_start = -1;
12
13extern const void bpf_link_fops __ksym;
14extern const void __start_BTF __ksym;
15extern const void __stop_BTF __ksym;
16extern const void __per_cpu_start __ksym;
17/* non-existing symbol, weak, default to zero */
18extern const void bpf_link_fops1 __ksym __weak;
19
20SEC("raw_tp/sys_enter")
21int handler(const void *ctx)
22{
23 out__bpf_link_fops = (__u64)&bpf_link_fops;
24 out__btf_size = (__u64)(&__stop_BTF - &__start_BTF);
25 out__per_cpu_start = (__u64)&__per_cpu_start;
26
27 out__bpf_link_fops1 = (__u64)&bpf_link_fops1;
28
29 return 0;
30}
31
32char _license[] SEC("license") = "GPL";