Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
3
4#ifndef _GNU_SOURCE
5#define _GNU_SOURCE
6#endif
7#include <errno.h>
8#include <fcntl.h>
9#include <signal.h>
10#include <stdarg.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <time.h>
15#include <unistd.h>
16#include <net/if.h>
17#include <sys/ioctl.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <sys/syscall.h>
21#include <dirent.h>
22
23#include <linux/err.h>
24#include <linux/perf_event.h>
25#include <linux/sizes.h>
26#include <linux/keyctl.h>
27
28#include <bpf/bpf.h>
29#include <bpf/btf.h>
30#include <bpf/hashmap.h>
31#include <bpf/libbpf.h>
32#include <bpf/libbpf_internal.h>
33#include <bpf/skel_internal.h>
34
35#include "cfg.h"
36#include "main.h"
37#include "xlated_dumper.h"
38
39#define BPF_METADATA_PREFIX "bpf_metadata_"
40#define BPF_METADATA_PREFIX_LEN (sizeof(BPF_METADATA_PREFIX) - 1)
41
42enum dump_mode {
43 DUMP_JITED,
44 DUMP_XLATED,
45};
46
47static const bool attach_types[] = {
48 [BPF_SK_SKB_STREAM_PARSER] = true,
49 [BPF_SK_SKB_STREAM_VERDICT] = true,
50 [BPF_SK_SKB_VERDICT] = true,
51 [BPF_SK_MSG_VERDICT] = true,
52 [BPF_FLOW_DISSECTOR] = true,
53 [__MAX_BPF_ATTACH_TYPE] = false,
54};
55
56/* Textual representations traditionally used by the program and kept around
57 * for the sake of backwards compatibility.
58 */
59static const char * const attach_type_strings[] = {
60 [BPF_SK_SKB_STREAM_PARSER] = "stream_parser",
61 [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict",
62 [BPF_SK_SKB_VERDICT] = "skb_verdict",
63 [BPF_SK_MSG_VERDICT] = "msg_verdict",
64 [__MAX_BPF_ATTACH_TYPE] = NULL,
65};
66
67static struct hashmap *prog_table;
68
69static enum bpf_attach_type parse_attach_type(const char *str)
70{
71 enum bpf_attach_type type;
72
73 for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
74 if (attach_types[type]) {
75 const char *attach_type_str;
76
77 attach_type_str = libbpf_bpf_attach_type_str(type);
78 if (!strcmp(str, attach_type_str))
79 return type;
80 }
81
82 if (attach_type_strings[type] &&
83 is_prefix(str, attach_type_strings[type]))
84 return type;
85 }
86
87 return __MAX_BPF_ATTACH_TYPE;
88}
89
90static int prep_prog_info(struct bpf_prog_info *const info, enum dump_mode mode,
91 void **info_data, size_t *const info_data_sz)
92{
93 struct bpf_prog_info holder = {};
94 size_t needed = 0;
95 void *ptr;
96
97 if (mode == DUMP_JITED) {
98 holder.jited_prog_len = info->jited_prog_len;
99 needed += info->jited_prog_len;
100 } else {
101 holder.xlated_prog_len = info->xlated_prog_len;
102 needed += info->xlated_prog_len;
103 }
104
105 holder.nr_jited_ksyms = info->nr_jited_ksyms;
106 needed += info->nr_jited_ksyms * sizeof(__u64);
107
108 holder.nr_jited_func_lens = info->nr_jited_func_lens;
109 needed += info->nr_jited_func_lens * sizeof(__u32);
110
111 holder.nr_func_info = info->nr_func_info;
112 holder.func_info_rec_size = info->func_info_rec_size;
113 needed += info->nr_func_info * info->func_info_rec_size;
114
115 holder.nr_line_info = info->nr_line_info;
116 holder.line_info_rec_size = info->line_info_rec_size;
117 needed += info->nr_line_info * info->line_info_rec_size;
118
119 holder.nr_jited_line_info = info->nr_jited_line_info;
120 holder.jited_line_info_rec_size = info->jited_line_info_rec_size;
121 needed += info->nr_jited_line_info * info->jited_line_info_rec_size;
122
123 if (needed > *info_data_sz) {
124 ptr = realloc(*info_data, needed);
125 if (!ptr)
126 return -1;
127
128 *info_data = ptr;
129 *info_data_sz = needed;
130 }
131 ptr = *info_data;
132
133 if (mode == DUMP_JITED) {
134 holder.jited_prog_insns = ptr_to_u64(ptr);
135 ptr += holder.jited_prog_len;
136 } else {
137 holder.xlated_prog_insns = ptr_to_u64(ptr);
138 ptr += holder.xlated_prog_len;
139 }
140
141 holder.jited_ksyms = ptr_to_u64(ptr);
142 ptr += holder.nr_jited_ksyms * sizeof(__u64);
143
144 holder.jited_func_lens = ptr_to_u64(ptr);
145 ptr += holder.nr_jited_func_lens * sizeof(__u32);
146
147 holder.func_info = ptr_to_u64(ptr);
148 ptr += holder.nr_func_info * holder.func_info_rec_size;
149
150 holder.line_info = ptr_to_u64(ptr);
151 ptr += holder.nr_line_info * holder.line_info_rec_size;
152
153 holder.jited_line_info = ptr_to_u64(ptr);
154 ptr += holder.nr_jited_line_info * holder.jited_line_info_rec_size;
155
156 *info = holder;
157 return 0;
158}
159
160static void print_boot_time(__u64 nsecs, char *buf, unsigned int size)
161{
162 struct timespec real_time_ts, boot_time_ts;
163 time_t wallclock_secs;
164 struct tm load_tm;
165
166 buf[--size] = '\0';
167
168 if (clock_gettime(CLOCK_REALTIME, &real_time_ts) ||
169 clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) {
170 perror("Can't read clocks");
171 snprintf(buf, size, "%llu", nsecs / 1000000000);
172 return;
173 }
174
175 wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) +
176 (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) /
177 1000000000;
178
179
180 if (!localtime_r(&wallclock_secs, &load_tm)) {
181 snprintf(buf, size, "%llu", nsecs / 1000000000);
182 return;
183 }
184
185 if (json_output)
186 strftime(buf, size, "%s", &load_tm);
187 else
188 strftime(buf, size, "%FT%T%z", &load_tm);
189}
190
191static void show_prog_maps(int fd, __u32 num_maps)
192{
193 struct bpf_prog_info info = {};
194 __u32 len = sizeof(info);
195 __u32 map_ids[num_maps];
196 unsigned int i;
197 int err;
198
199 info.nr_map_ids = num_maps;
200 info.map_ids = ptr_to_u64(map_ids);
201
202 err = bpf_prog_get_info_by_fd(fd, &info, &len);
203 if (err || !info.nr_map_ids)
204 return;
205
206 if (json_output) {
207 jsonw_name(json_wtr, "map_ids");
208 jsonw_start_array(json_wtr);
209 for (i = 0; i < info.nr_map_ids; i++)
210 jsonw_uint(json_wtr, map_ids[i]);
211 jsonw_end_array(json_wtr);
212 } else {
213 printf(" map_ids ");
214 for (i = 0; i < info.nr_map_ids; i++)
215 printf("%u%s", map_ids[i],
216 i == info.nr_map_ids - 1 ? "" : ",");
217 }
218}
219
220static void *find_metadata(int prog_fd, struct bpf_map_info *map_info)
221{
222 struct bpf_prog_info prog_info;
223 __u32 prog_info_len;
224 __u32 map_info_len;
225 void *value = NULL;
226 __u32 *map_ids;
227 int nr_maps;
228 int key = 0;
229 int map_fd;
230 int ret;
231 __u32 i;
232
233 memset(&prog_info, 0, sizeof(prog_info));
234 prog_info_len = sizeof(prog_info);
235 ret = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &prog_info_len);
236 if (ret)
237 return NULL;
238
239 if (!prog_info.nr_map_ids)
240 return NULL;
241
242 map_ids = calloc(prog_info.nr_map_ids, sizeof(__u32));
243 if (!map_ids)
244 return NULL;
245
246 nr_maps = prog_info.nr_map_ids;
247 memset(&prog_info, 0, sizeof(prog_info));
248 prog_info.nr_map_ids = nr_maps;
249 prog_info.map_ids = ptr_to_u64(map_ids);
250 prog_info_len = sizeof(prog_info);
251
252 ret = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &prog_info_len);
253 if (ret)
254 goto free_map_ids;
255
256 for (i = 0; i < prog_info.nr_map_ids; i++) {
257 map_fd = bpf_map_get_fd_by_id(map_ids[i]);
258 if (map_fd < 0)
259 goto free_map_ids;
260
261 memset(map_info, 0, sizeof(*map_info));
262 map_info_len = sizeof(*map_info);
263 ret = bpf_map_get_info_by_fd(map_fd, map_info, &map_info_len);
264 if (ret < 0) {
265 close(map_fd);
266 goto free_map_ids;
267 }
268
269 if (map_info->type != BPF_MAP_TYPE_ARRAY ||
270 map_info->key_size != sizeof(int) ||
271 map_info->max_entries != 1 ||
272 !map_info->btf_value_type_id ||
273 !strstr(map_info->name, ".rodata")) {
274 close(map_fd);
275 continue;
276 }
277
278 value = malloc(map_info->value_size);
279 if (!value) {
280 close(map_fd);
281 goto free_map_ids;
282 }
283
284 if (bpf_map_lookup_elem(map_fd, &key, value)) {
285 close(map_fd);
286 free(value);
287 value = NULL;
288 goto free_map_ids;
289 }
290
291 close(map_fd);
292 break;
293 }
294
295free_map_ids:
296 free(map_ids);
297 return value;
298}
299
300static bool has_metadata_prefix(const char *s)
301{
302 return strncmp(s, BPF_METADATA_PREFIX, BPF_METADATA_PREFIX_LEN) == 0;
303}
304
305static void show_prog_metadata(int fd, __u32 num_maps)
306{
307 const struct btf_type *t_datasec, *t_var;
308 struct bpf_map_info map_info;
309 struct btf_var_secinfo *vsi;
310 bool printed_header = false;
311 unsigned int i, vlen;
312 void *value = NULL;
313 const char *name;
314 struct btf *btf;
315 int err;
316
317 if (!num_maps)
318 return;
319
320 memset(&map_info, 0, sizeof(map_info));
321 value = find_metadata(fd, &map_info);
322 if (!value)
323 return;
324
325 btf = btf__load_from_kernel_by_id(map_info.btf_id);
326 if (!btf)
327 goto out_free;
328
329 t_datasec = btf__type_by_id(btf, map_info.btf_value_type_id);
330 if (!btf_is_datasec(t_datasec))
331 goto out_free;
332
333 vlen = btf_vlen(t_datasec);
334 vsi = btf_var_secinfos(t_datasec);
335
336 /* We don't proceed to check the kinds of the elements of the DATASEC.
337 * The verifier enforces them to be BTF_KIND_VAR.
338 */
339
340 if (json_output) {
341 struct btf_dumper d = {
342 .btf = btf,
343 .jw = json_wtr,
344 .is_plain_text = false,
345 };
346
347 for (i = 0; i < vlen; i++, vsi++) {
348 t_var = btf__type_by_id(btf, vsi->type);
349 name = btf__name_by_offset(btf, t_var->name_off);
350
351 if (!has_metadata_prefix(name))
352 continue;
353
354 if (!printed_header) {
355 jsonw_name(json_wtr, "metadata");
356 jsonw_start_object(json_wtr);
357 printed_header = true;
358 }
359
360 jsonw_name(json_wtr, name + BPF_METADATA_PREFIX_LEN);
361 err = btf_dumper_type(&d, t_var->type, value + vsi->offset);
362 if (err) {
363 p_err("btf dump failed: %d", err);
364 break;
365 }
366 }
367 if (printed_header)
368 jsonw_end_object(json_wtr);
369 } else {
370 json_writer_t *btf_wtr;
371 struct btf_dumper d = {
372 .btf = btf,
373 .is_plain_text = true,
374 };
375
376 for (i = 0; i < vlen; i++, vsi++) {
377 t_var = btf__type_by_id(btf, vsi->type);
378 name = btf__name_by_offset(btf, t_var->name_off);
379
380 if (!has_metadata_prefix(name))
381 continue;
382
383 if (!printed_header) {
384 printf("\tmetadata:");
385
386 btf_wtr = jsonw_new(stdout);
387 if (!btf_wtr) {
388 p_err("jsonw alloc failed");
389 goto out_free;
390 }
391 d.jw = btf_wtr,
392
393 printed_header = true;
394 }
395
396 printf("\n\t\t%s = ", name + BPF_METADATA_PREFIX_LEN);
397
398 jsonw_reset(btf_wtr);
399 err = btf_dumper_type(&d, t_var->type, value + vsi->offset);
400 if (err) {
401 p_err("btf dump failed: %d", err);
402 break;
403 }
404 }
405 if (printed_header)
406 jsonw_destroy(&btf_wtr);
407 }
408
409out_free:
410 btf__free(btf);
411 free(value);
412}
413
414static void print_prog_header_json(struct bpf_prog_info *info, int fd)
415{
416 const char *prog_type_str;
417 char prog_name[MAX_PROG_FULL_NAME];
418
419 jsonw_uint_field(json_wtr, "id", info->id);
420 prog_type_str = libbpf_bpf_prog_type_str(info->type);
421
422 if (prog_type_str)
423 jsonw_string_field(json_wtr, "type", prog_type_str);
424 else
425 jsonw_uint_field(json_wtr, "type", info->type);
426
427 if (*info->name) {
428 get_prog_full_name(info, fd, prog_name, sizeof(prog_name));
429 jsonw_string_field(json_wtr, "name", prog_name);
430 }
431
432 jsonw_name(json_wtr, "tag");
433 jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"",
434 info->tag[0], info->tag[1], info->tag[2], info->tag[3],
435 info->tag[4], info->tag[5], info->tag[6], info->tag[7]);
436
437 jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible);
438 if (info->run_time_ns) {
439 jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns);
440 jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt);
441 }
442 if (info->recursion_misses)
443 jsonw_uint_field(json_wtr, "recursion_misses", info->recursion_misses);
444}
445
446static void print_prog_json(struct bpf_prog_info *info, int fd, bool orphaned)
447{
448 char *memlock;
449
450 jsonw_start_object(json_wtr);
451 print_prog_header_json(info, fd);
452 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
453
454 if (info->load_time) {
455 char buf[32];
456
457 print_boot_time(info->load_time, buf, sizeof(buf));
458
459 /* Piggy back on load_time, since 0 uid is a valid one */
460 jsonw_name(json_wtr, "loaded_at");
461 jsonw_printf(json_wtr, "%s", buf);
462 jsonw_uint_field(json_wtr, "uid", info->created_by_uid);
463 }
464
465 jsonw_bool_field(json_wtr, "orphaned", orphaned);
466 jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len);
467
468 if (info->jited_prog_len) {
469 jsonw_bool_field(json_wtr, "jited", true);
470 jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len);
471 } else {
472 jsonw_bool_field(json_wtr, "jited", false);
473 }
474
475 memlock = get_fdinfo(fd, "memlock");
476 if (memlock)
477 jsonw_int_field(json_wtr, "bytes_memlock", atoll(memlock));
478 free(memlock);
479
480 if (info->nr_map_ids)
481 show_prog_maps(fd, info->nr_map_ids);
482
483 if (info->btf_id)
484 jsonw_int_field(json_wtr, "btf_id", info->btf_id);
485
486 if (!hashmap__empty(prog_table)) {
487 struct hashmap_entry *entry;
488
489 jsonw_name(json_wtr, "pinned");
490 jsonw_start_array(json_wtr);
491 hashmap__for_each_key_entry(prog_table, entry, info->id)
492 jsonw_string(json_wtr, entry->pvalue);
493 jsonw_end_array(json_wtr);
494 }
495
496 emit_obj_refs_json(refs_table, info->id, json_wtr);
497
498 show_prog_metadata(fd, info->nr_map_ids);
499
500 jsonw_end_object(json_wtr);
501}
502
503static void print_prog_header_plain(struct bpf_prog_info *info, int fd)
504{
505 const char *prog_type_str;
506 char prog_name[MAX_PROG_FULL_NAME];
507
508 printf("%u: ", info->id);
509 prog_type_str = libbpf_bpf_prog_type_str(info->type);
510 if (prog_type_str)
511 printf("%s ", prog_type_str);
512 else
513 printf("type %u ", info->type);
514
515 if (*info->name) {
516 get_prog_full_name(info, fd, prog_name, sizeof(prog_name));
517 printf("name %s ", prog_name);
518 }
519
520 printf("tag ");
521 fprint_hex(stdout, info->tag, BPF_TAG_SIZE, "");
522 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
523 printf("%s", info->gpl_compatible ? " gpl" : "");
524 if (info->run_time_ns)
525 printf(" run_time_ns %llu run_cnt %llu",
526 info->run_time_ns, info->run_cnt);
527 if (info->recursion_misses)
528 printf(" recursion_misses %llu", info->recursion_misses);
529 printf("\n");
530}
531
532static void print_prog_plain(struct bpf_prog_info *info, int fd, bool orphaned)
533{
534 char *memlock;
535
536 print_prog_header_plain(info, fd);
537
538 if (info->load_time) {
539 char buf[32];
540
541 print_boot_time(info->load_time, buf, sizeof(buf));
542
543 /* Piggy back on load_time, since 0 uid is a valid one */
544 printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid);
545 }
546
547 printf("\txlated %uB", info->xlated_prog_len);
548
549 if (info->jited_prog_len)
550 printf(" jited %uB", info->jited_prog_len);
551 else
552 printf(" not jited");
553
554 memlock = get_fdinfo(fd, "memlock");
555 if (memlock)
556 printf(" memlock %sB", memlock);
557 free(memlock);
558
559 if (orphaned)
560 printf(" orphaned");
561
562 if (info->nr_map_ids)
563 show_prog_maps(fd, info->nr_map_ids);
564
565 if (!hashmap__empty(prog_table)) {
566 struct hashmap_entry *entry;
567
568 hashmap__for_each_key_entry(prog_table, entry, info->id)
569 printf("\n\tpinned %s", (char *)entry->pvalue);
570 }
571
572 if (info->btf_id)
573 printf("\n\tbtf_id %u", info->btf_id);
574
575 emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
576
577 printf("\n");
578
579 show_prog_metadata(fd, info->nr_map_ids);
580}
581
582static int show_prog(int fd)
583{
584 struct bpf_prog_info info = {};
585 __u32 len = sizeof(info);
586 int err;
587
588 err = bpf_prog_get_info_by_fd(fd, &info, &len);
589 if (err && err != -ENODEV) {
590 p_err("can't get prog info: %s", strerror(errno));
591 return -1;
592 }
593
594 if (json_output)
595 print_prog_json(&info, fd, err == -ENODEV);
596 else
597 print_prog_plain(&info, fd, err == -ENODEV);
598
599 return 0;
600}
601
602static int do_show_subset(int argc, char **argv)
603{
604 int *fds = NULL;
605 int nb_fds, i;
606 int err = -1;
607
608 fds = malloc(sizeof(int));
609 if (!fds) {
610 p_err("mem alloc failed");
611 return -1;
612 }
613 nb_fds = prog_parse_fds(&argc, &argv, &fds);
614 if (nb_fds < 1)
615 goto exit_free;
616
617 if (json_output && nb_fds > 1)
618 jsonw_start_array(json_wtr); /* root array */
619 for (i = 0; i < nb_fds; i++) {
620 err = show_prog(fds[i]);
621 if (err) {
622 for (; i < nb_fds; i++)
623 close(fds[i]);
624 break;
625 }
626 close(fds[i]);
627 }
628 if (json_output && nb_fds > 1)
629 jsonw_end_array(json_wtr); /* root array */
630
631exit_free:
632 free(fds);
633 return err;
634}
635
636static int do_show(int argc, char **argv)
637{
638 __u32 id = 0;
639 int err;
640 int fd;
641
642 if (show_pinned) {
643 prog_table = hashmap__new(hash_fn_for_key_as_id,
644 equal_fn_for_key_as_id, NULL);
645 if (IS_ERR(prog_table)) {
646 p_err("failed to create hashmap for pinned paths");
647 return -1;
648 }
649 build_pinned_obj_table(prog_table, BPF_OBJ_PROG);
650 }
651 build_obj_refs_table(&refs_table, BPF_OBJ_PROG);
652
653 if (argc == 2)
654 return do_show_subset(argc, argv);
655
656 if (argc)
657 return BAD_ARG();
658
659 if (json_output)
660 jsonw_start_array(json_wtr);
661 while (true) {
662 err = bpf_prog_get_next_id(id, &id);
663 if (err) {
664 if (errno == ENOENT) {
665 err = 0;
666 break;
667 }
668 p_err("can't get next program: %s%s", strerror(errno),
669 errno == EINVAL ? " -- kernel too old?" : "");
670 err = -1;
671 break;
672 }
673
674 fd = bpf_prog_get_fd_by_id(id);
675 if (fd < 0) {
676 if (errno == ENOENT)
677 continue;
678 p_err("can't get prog by id (%u): %s",
679 id, strerror(errno));
680 err = -1;
681 break;
682 }
683
684 err = show_prog(fd);
685 close(fd);
686 if (err)
687 break;
688 }
689
690 if (json_output)
691 jsonw_end_array(json_wtr);
692
693 delete_obj_refs_table(refs_table);
694
695 if (show_pinned)
696 delete_pinned_obj_table(prog_table);
697
698 return err;
699}
700
701static int
702prog_dump(struct bpf_prog_info *info, enum dump_mode mode,
703 char *filepath, bool opcodes, bool visual, bool linum)
704{
705 struct bpf_prog_linfo *prog_linfo = NULL;
706 const char *disasm_opt = NULL;
707 struct dump_data dd = {};
708 void *func_info = NULL;
709 struct btf *btf = NULL;
710 char func_sig[1024];
711 unsigned char *buf;
712 __u32 member_len;
713 int fd, err = -1;
714 ssize_t n;
715
716 if (mode == DUMP_JITED) {
717 if (info->jited_prog_len == 0 || !info->jited_prog_insns) {
718 p_err("error retrieving jit dump: no instructions returned or kernel.kptr_restrict set?");
719 return -1;
720 }
721 buf = u64_to_ptr(info->jited_prog_insns);
722 member_len = info->jited_prog_len;
723 } else { /* DUMP_XLATED */
724 if (info->xlated_prog_len == 0 || !info->xlated_prog_insns) {
725 p_err("error retrieving insn dump: kernel.kptr_restrict set?");
726 return -1;
727 }
728 buf = u64_to_ptr(info->xlated_prog_insns);
729 member_len = info->xlated_prog_len;
730 }
731
732 if (info->btf_id) {
733 btf = btf__load_from_kernel_by_id(info->btf_id);
734 if (!btf) {
735 p_err("failed to get btf");
736 return -1;
737 }
738 }
739
740 func_info = u64_to_ptr(info->func_info);
741
742 if (info->nr_line_info) {
743 prog_linfo = bpf_prog_linfo__new(info);
744 if (!prog_linfo)
745 p_info("error in processing bpf_line_info. continue without it.");
746 }
747
748 if (filepath) {
749 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
750 if (fd < 0) {
751 p_err("can't open file %s: %s", filepath,
752 strerror(errno));
753 goto exit_free;
754 }
755
756 n = write(fd, buf, member_len);
757 close(fd);
758 if (n != (ssize_t)member_len) {
759 p_err("error writing output file: %s",
760 n < 0 ? strerror(errno) : "short write");
761 goto exit_free;
762 }
763
764 if (json_output)
765 jsonw_null(json_wtr);
766 } else if (mode == DUMP_JITED) {
767 const char *name = NULL;
768
769 if (info->ifindex) {
770 name = ifindex_to_arch(info->ifindex, info->netns_dev,
771 info->netns_ino, &disasm_opt);
772 if (!name)
773 goto exit_free;
774 }
775
776 if (info->nr_jited_func_lens && info->jited_func_lens) {
777 struct kernel_sym *sym = NULL;
778 struct bpf_func_info *record;
779 char sym_name[SYM_MAX_NAME];
780 unsigned char *img = buf;
781 __u64 *ksyms = NULL;
782 __u32 *lens;
783 __u32 i;
784 if (info->nr_jited_ksyms) {
785 kernel_syms_load(&dd);
786 ksyms = u64_to_ptr(info->jited_ksyms);
787 }
788
789 if (json_output)
790 jsonw_start_array(json_wtr);
791
792 lens = u64_to_ptr(info->jited_func_lens);
793 for (i = 0; i < info->nr_jited_func_lens; i++) {
794 if (ksyms) {
795 sym = kernel_syms_search(&dd, ksyms[i]);
796 if (sym)
797 sprintf(sym_name, "%s", sym->name);
798 else
799 sprintf(sym_name, "0x%016llx", ksyms[i]);
800 } else {
801 strcpy(sym_name, "unknown");
802 }
803
804 if (func_info) {
805 record = func_info + i * info->func_info_rec_size;
806 btf_dumper_type_only(btf, record->type_id,
807 func_sig,
808 sizeof(func_sig));
809 }
810
811 if (json_output) {
812 jsonw_start_object(json_wtr);
813 if (func_info && func_sig[0] != '\0') {
814 jsonw_name(json_wtr, "proto");
815 jsonw_string(json_wtr, func_sig);
816 }
817 jsonw_name(json_wtr, "name");
818 jsonw_string(json_wtr, sym_name);
819 jsonw_name(json_wtr, "insns");
820 } else {
821 if (func_info && func_sig[0] != '\0')
822 printf("%s:\n", func_sig);
823 printf("%s:\n", sym_name);
824 }
825
826 if (ksyms) {
827 if (disasm_print_insn(img, lens[i], opcodes,
828 name, disasm_opt, btf,
829 prog_linfo, ksyms[i], i,
830 linum))
831 goto exit_free;
832 } else {
833 if (disasm_print_insn(img, lens[i], opcodes,
834 name, disasm_opt, btf,
835 NULL, 0, 0, false))
836 goto exit_free;
837 }
838
839 img += lens[i];
840
841 if (json_output)
842 jsonw_end_object(json_wtr);
843 else
844 printf("\n");
845 }
846
847 if (json_output)
848 jsonw_end_array(json_wtr);
849 } else {
850 if (disasm_print_insn(buf, member_len, opcodes, name,
851 disasm_opt, btf, NULL, 0, 0,
852 false))
853 goto exit_free;
854 }
855 } else {
856 kernel_syms_load(&dd);
857 dd.nr_jited_ksyms = info->nr_jited_ksyms;
858 dd.jited_ksyms = u64_to_ptr(info->jited_ksyms);
859 dd.btf = btf;
860 dd.func_info = func_info;
861 dd.finfo_rec_size = info->func_info_rec_size;
862 dd.prog_linfo = prog_linfo;
863
864 if (json_output)
865 dump_xlated_json(&dd, buf, member_len, opcodes, linum);
866 else if (visual)
867 dump_xlated_cfg(&dd, buf, member_len, opcodes, linum);
868 else
869 dump_xlated_plain(&dd, buf, member_len, opcodes, linum);
870 kernel_syms_destroy(&dd);
871 }
872
873 err = 0;
874
875exit_free:
876 btf__free(btf);
877 bpf_prog_linfo__free(prog_linfo);
878 return err;
879}
880
881static int do_dump(int argc, char **argv)
882{
883 struct bpf_prog_info info;
884 __u32 info_len = sizeof(info);
885 size_t info_data_sz = 0;
886 void *info_data = NULL;
887 char *filepath = NULL;
888 bool opcodes = false;
889 bool visual = false;
890 enum dump_mode mode;
891 bool linum = false;
892 int nb_fds, i = 0;
893 int *fds = NULL;
894 int err = -1;
895
896 if (is_prefix(*argv, "jited")) {
897 if (disasm_init())
898 return -1;
899 mode = DUMP_JITED;
900 } else if (is_prefix(*argv, "xlated")) {
901 mode = DUMP_XLATED;
902 } else {
903 p_err("expected 'xlated' or 'jited', got: %s", *argv);
904 return -1;
905 }
906 NEXT_ARG();
907
908 if (argc < 2)
909 usage();
910
911 fds = malloc(sizeof(int));
912 if (!fds) {
913 p_err("mem alloc failed");
914 return -1;
915 }
916 nb_fds = prog_parse_fds(&argc, &argv, &fds);
917 if (nb_fds < 1)
918 goto exit_free;
919
920 while (argc) {
921 if (is_prefix(*argv, "file")) {
922 NEXT_ARG();
923 if (!argc) {
924 p_err("expected file path");
925 goto exit_close;
926 }
927 if (nb_fds > 1) {
928 p_err("several programs matched");
929 goto exit_close;
930 }
931
932 filepath = *argv;
933 NEXT_ARG();
934 } else if (is_prefix(*argv, "opcodes")) {
935 opcodes = true;
936 NEXT_ARG();
937 } else if (is_prefix(*argv, "visual")) {
938 if (nb_fds > 1) {
939 p_err("several programs matched");
940 goto exit_close;
941 }
942
943 visual = true;
944 NEXT_ARG();
945 } else if (is_prefix(*argv, "linum")) {
946 linum = true;
947 NEXT_ARG();
948 } else {
949 usage();
950 goto exit_close;
951 }
952 }
953
954 if (filepath && (opcodes || visual || linum)) {
955 p_err("'file' is not compatible with 'opcodes', 'visual', or 'linum'");
956 goto exit_close;
957 }
958 if (json_output && visual) {
959 p_err("'visual' is not compatible with JSON output");
960 goto exit_close;
961 }
962
963 if (json_output && nb_fds > 1)
964 jsonw_start_array(json_wtr); /* root array */
965 for (i = 0; i < nb_fds; i++) {
966 memset(&info, 0, sizeof(info));
967
968 err = bpf_prog_get_info_by_fd(fds[i], &info, &info_len);
969 if (err) {
970 p_err("can't get prog info: %s", strerror(errno));
971 break;
972 }
973
974 err = prep_prog_info(&info, mode, &info_data, &info_data_sz);
975 if (err) {
976 p_err("can't grow prog info_data");
977 break;
978 }
979
980 err = bpf_prog_get_info_by_fd(fds[i], &info, &info_len);
981 if (err) {
982 p_err("can't get prog info: %s", strerror(errno));
983 break;
984 }
985
986 if (json_output && nb_fds > 1) {
987 jsonw_start_object(json_wtr); /* prog object */
988 print_prog_header_json(&info, fds[i]);
989 jsonw_name(json_wtr, "insns");
990 } else if (nb_fds > 1) {
991 print_prog_header_plain(&info, fds[i]);
992 }
993
994 err = prog_dump(&info, mode, filepath, opcodes, visual, linum);
995
996 if (json_output && nb_fds > 1)
997 jsonw_end_object(json_wtr); /* prog object */
998 else if (i != nb_fds - 1 && nb_fds > 1)
999 printf("\n");
1000
1001 if (err)
1002 break;
1003 close(fds[i]);
1004 }
1005 if (json_output && nb_fds > 1)
1006 jsonw_end_array(json_wtr); /* root array */
1007
1008exit_close:
1009 for (; i < nb_fds; i++)
1010 close(fds[i]);
1011exit_free:
1012 free(info_data);
1013 free(fds);
1014 return err;
1015}
1016
1017static int do_pin(int argc, char **argv)
1018{
1019 int err;
1020
1021 err = do_pin_any(argc, argv, prog_parse_fd);
1022 if (!err && json_output)
1023 jsonw_null(json_wtr);
1024 return err;
1025}
1026
1027struct map_replace {
1028 int idx;
1029 int fd;
1030 char *name;
1031};
1032
1033static int map_replace_compar(const void *p1, const void *p2)
1034{
1035 const struct map_replace *a = p1, *b = p2;
1036
1037 return a->idx - b->idx;
1038}
1039
1040static int parse_attach_detach_args(int argc, char **argv, int *progfd,
1041 enum bpf_attach_type *attach_type,
1042 int *mapfd)
1043{
1044 if (!REQ_ARGS(3))
1045 return -EINVAL;
1046
1047 *progfd = prog_parse_fd(&argc, &argv);
1048 if (*progfd < 0)
1049 return *progfd;
1050
1051 *attach_type = parse_attach_type(*argv);
1052 if (*attach_type == __MAX_BPF_ATTACH_TYPE) {
1053 p_err("invalid attach/detach type");
1054 return -EINVAL;
1055 }
1056
1057 if (*attach_type == BPF_FLOW_DISSECTOR) {
1058 *mapfd = 0;
1059 return 0;
1060 }
1061
1062 NEXT_ARG();
1063 if (!REQ_ARGS(2))
1064 return -EINVAL;
1065
1066 *mapfd = map_parse_fd(&argc, &argv, 0);
1067 if (*mapfd < 0)
1068 return *mapfd;
1069
1070 return 0;
1071}
1072
1073static int do_attach(int argc, char **argv)
1074{
1075 enum bpf_attach_type attach_type;
1076 int err, progfd;
1077 int mapfd;
1078
1079 err = parse_attach_detach_args(argc, argv,
1080 &progfd, &attach_type, &mapfd);
1081 if (err)
1082 return err;
1083
1084 err = bpf_prog_attach(progfd, mapfd, attach_type, 0);
1085 if (err) {
1086 p_err("failed prog attach to map");
1087 return -EINVAL;
1088 }
1089
1090 if (json_output)
1091 jsonw_null(json_wtr);
1092 return 0;
1093}
1094
1095static int do_detach(int argc, char **argv)
1096{
1097 enum bpf_attach_type attach_type;
1098 int err, progfd;
1099 int mapfd;
1100
1101 err = parse_attach_detach_args(argc, argv,
1102 &progfd, &attach_type, &mapfd);
1103 if (err)
1104 return err;
1105
1106 err = bpf_prog_detach2(progfd, mapfd, attach_type);
1107 if (err) {
1108 p_err("failed prog detach from map");
1109 return -EINVAL;
1110 }
1111
1112 if (json_output)
1113 jsonw_null(json_wtr);
1114 return 0;
1115}
1116
1117enum prog_tracelog_mode {
1118 TRACE_STDOUT,
1119 TRACE_STDERR,
1120};
1121
1122static int
1123prog_tracelog_stream(int prog_fd, enum prog_tracelog_mode mode)
1124{
1125 FILE *file = mode == TRACE_STDOUT ? stdout : stderr;
1126 int stream_id = mode == TRACE_STDOUT ? 1 : 2;
1127 char buf[512];
1128 int ret;
1129
1130 ret = 0;
1131 do {
1132 ret = bpf_prog_stream_read(prog_fd, stream_id, buf, sizeof(buf), NULL);
1133 if (ret > 0)
1134 fwrite(buf, sizeof(buf[0]), ret, file);
1135 } while (ret > 0);
1136
1137 fflush(file);
1138 return ret ? -1 : 0;
1139}
1140
1141static int do_tracelog_any(int argc, char **argv)
1142{
1143 enum prog_tracelog_mode mode;
1144 int fd;
1145
1146 if (argc == 0)
1147 return do_tracelog(argc, argv);
1148 if (!is_prefix(*argv, "stdout") && !is_prefix(*argv, "stderr"))
1149 usage();
1150 mode = is_prefix(*argv, "stdout") ? TRACE_STDOUT : TRACE_STDERR;
1151 NEXT_ARG();
1152
1153 if (!REQ_ARGS(2))
1154 return -1;
1155
1156 fd = prog_parse_fd(&argc, &argv);
1157 if (fd < 0)
1158 return -1;
1159
1160 return prog_tracelog_stream(fd, mode);
1161}
1162
1163static int check_single_stdin(char *file_data_in, char *file_ctx_in)
1164{
1165 if (file_data_in && file_ctx_in &&
1166 !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) {
1167 p_err("cannot use standard input for both data_in and ctx_in");
1168 return -1;
1169 }
1170
1171 return 0;
1172}
1173
1174static int get_run_data(const char *fname, void **data_ptr, unsigned int *size)
1175{
1176 size_t block_size = 256;
1177 size_t buf_size = block_size;
1178 size_t nb_read = 0;
1179 void *tmp;
1180 FILE *f;
1181
1182 if (!fname) {
1183 *data_ptr = NULL;
1184 *size = 0;
1185 return 0;
1186 }
1187
1188 if (!strcmp(fname, "-"))
1189 f = stdin;
1190 else
1191 f = fopen(fname, "r");
1192 if (!f) {
1193 p_err("failed to open %s: %s", fname, strerror(errno));
1194 return -1;
1195 }
1196
1197 *data_ptr = malloc(block_size);
1198 if (!*data_ptr) {
1199 p_err("failed to allocate memory for data_in/ctx_in: %s",
1200 strerror(errno));
1201 goto err_fclose;
1202 }
1203
1204 while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) {
1205 if (feof(f))
1206 break;
1207 if (ferror(f)) {
1208 p_err("failed to read data_in/ctx_in from %s: %s",
1209 fname, strerror(errno));
1210 goto err_free;
1211 }
1212 if (nb_read > buf_size - block_size) {
1213 if (buf_size == UINT32_MAX) {
1214 p_err("data_in/ctx_in is too long (max: %u)",
1215 UINT32_MAX);
1216 goto err_free;
1217 }
1218 /* No space for fread()-ing next chunk; realloc() */
1219 buf_size *= 2;
1220 tmp = realloc(*data_ptr, buf_size);
1221 if (!tmp) {
1222 p_err("failed to reallocate data_in/ctx_in: %s",
1223 strerror(errno));
1224 goto err_free;
1225 }
1226 *data_ptr = tmp;
1227 }
1228 }
1229 if (f != stdin)
1230 fclose(f);
1231
1232 *size = nb_read;
1233 return 0;
1234
1235err_free:
1236 free(*data_ptr);
1237 *data_ptr = NULL;
1238err_fclose:
1239 if (f != stdin)
1240 fclose(f);
1241 return -1;
1242}
1243
1244static void hex_print(void *data, unsigned int size, FILE *f)
1245{
1246 size_t i, j;
1247 char c;
1248
1249 for (i = 0; i < size; i += 16) {
1250 /* Row offset */
1251 fprintf(f, "%07zx\t", i);
1252
1253 /* Hexadecimal values */
1254 for (j = i; j < i + 16 && j < size; j++)
1255 fprintf(f, "%02x%s", *(uint8_t *)(data + j),
1256 j % 2 ? " " : "");
1257 for (; j < i + 16; j++)
1258 fprintf(f, " %s", j % 2 ? " " : "");
1259
1260 /* ASCII values (if relevant), '.' otherwise */
1261 fprintf(f, "| ");
1262 for (j = i; j < i + 16 && j < size; j++) {
1263 c = *(char *)(data + j);
1264 if (c < ' ' || c > '~')
1265 c = '.';
1266 fprintf(f, "%c%s", c, j == i + 7 ? " " : "");
1267 }
1268
1269 fprintf(f, "\n");
1270 }
1271}
1272
1273static int
1274print_run_output(void *data, unsigned int size, const char *fname,
1275 const char *json_key)
1276{
1277 size_t nb_written;
1278 FILE *f;
1279
1280 if (!fname)
1281 return 0;
1282
1283 if (!strcmp(fname, "-")) {
1284 f = stdout;
1285 if (json_output) {
1286 jsonw_name(json_wtr, json_key);
1287 print_data_json(data, size);
1288 } else {
1289 hex_print(data, size, f);
1290 }
1291 return 0;
1292 }
1293
1294 f = fopen(fname, "w");
1295 if (!f) {
1296 p_err("failed to open %s: %s", fname, strerror(errno));
1297 return -1;
1298 }
1299
1300 nb_written = fwrite(data, 1, size, f);
1301 fclose(f);
1302 if (nb_written != size) {
1303 p_err("failed to write output data/ctx: %s", strerror(errno));
1304 return -1;
1305 }
1306
1307 return 0;
1308}
1309
1310static int alloc_run_data(void **data_ptr, unsigned int size_out)
1311{
1312 *data_ptr = calloc(size_out, 1);
1313 if (!*data_ptr) {
1314 p_err("failed to allocate memory for output data/ctx: %s",
1315 strerror(errno));
1316 return -1;
1317 }
1318
1319 return 0;
1320}
1321
1322static int do_run(int argc, char **argv)
1323{
1324 char *data_fname_in = NULL, *data_fname_out = NULL;
1325 char *ctx_fname_in = NULL, *ctx_fname_out = NULL;
1326 const unsigned int default_size = SZ_32K;
1327 void *data_in = NULL, *data_out = NULL;
1328 void *ctx_in = NULL, *ctx_out = NULL;
1329 unsigned int repeat = 1;
1330 int fd, err;
1331 LIBBPF_OPTS(bpf_test_run_opts, test_attr);
1332
1333 if (!REQ_ARGS(4))
1334 return -1;
1335
1336 fd = prog_parse_fd(&argc, &argv);
1337 if (fd < 0)
1338 return -1;
1339
1340 while (argc) {
1341 if (detect_common_prefix(*argv, "data_in", "data_out",
1342 "data_size_out", NULL))
1343 return -1;
1344 if (detect_common_prefix(*argv, "ctx_in", "ctx_out",
1345 "ctx_size_out", NULL))
1346 return -1;
1347
1348 if (is_prefix(*argv, "data_in")) {
1349 NEXT_ARG();
1350 if (!REQ_ARGS(1))
1351 return -1;
1352
1353 data_fname_in = GET_ARG();
1354 if (check_single_stdin(data_fname_in, ctx_fname_in))
1355 return -1;
1356 } else if (is_prefix(*argv, "data_out")) {
1357 NEXT_ARG();
1358 if (!REQ_ARGS(1))
1359 return -1;
1360
1361 data_fname_out = GET_ARG();
1362 } else if (is_prefix(*argv, "data_size_out")) {
1363 char *endptr;
1364
1365 NEXT_ARG();
1366 if (!REQ_ARGS(1))
1367 return -1;
1368
1369 test_attr.data_size_out = strtoul(*argv, &endptr, 0);
1370 if (*endptr) {
1371 p_err("can't parse %s as output data size",
1372 *argv);
1373 return -1;
1374 }
1375 NEXT_ARG();
1376 } else if (is_prefix(*argv, "ctx_in")) {
1377 NEXT_ARG();
1378 if (!REQ_ARGS(1))
1379 return -1;
1380
1381 ctx_fname_in = GET_ARG();
1382 if (check_single_stdin(data_fname_in, ctx_fname_in))
1383 return -1;
1384 } else if (is_prefix(*argv, "ctx_out")) {
1385 NEXT_ARG();
1386 if (!REQ_ARGS(1))
1387 return -1;
1388
1389 ctx_fname_out = GET_ARG();
1390 } else if (is_prefix(*argv, "ctx_size_out")) {
1391 char *endptr;
1392
1393 NEXT_ARG();
1394 if (!REQ_ARGS(1))
1395 return -1;
1396
1397 test_attr.ctx_size_out = strtoul(*argv, &endptr, 0);
1398 if (*endptr) {
1399 p_err("can't parse %s as output context size",
1400 *argv);
1401 return -1;
1402 }
1403 NEXT_ARG();
1404 } else if (is_prefix(*argv, "repeat")) {
1405 char *endptr;
1406
1407 NEXT_ARG();
1408 if (!REQ_ARGS(1))
1409 return -1;
1410
1411 repeat = strtoul(*argv, &endptr, 0);
1412 if (*endptr) {
1413 p_err("can't parse %s as repeat number",
1414 *argv);
1415 return -1;
1416 }
1417 NEXT_ARG();
1418 } else {
1419 p_err("expected no more arguments, 'data_in', 'data_out', 'data_size_out', 'ctx_in', 'ctx_out', 'ctx_size_out' or 'repeat', got: '%s'?",
1420 *argv);
1421 return -1;
1422 }
1423 }
1424
1425 err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in);
1426 if (err)
1427 return -1;
1428
1429 if (data_in) {
1430 if (!test_attr.data_size_out)
1431 test_attr.data_size_out = default_size;
1432 err = alloc_run_data(&data_out, test_attr.data_size_out);
1433 if (err)
1434 goto free_data_in;
1435 }
1436
1437 err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in);
1438 if (err)
1439 goto free_data_out;
1440
1441 if (ctx_in) {
1442 if (!test_attr.ctx_size_out)
1443 test_attr.ctx_size_out = default_size;
1444 err = alloc_run_data(&ctx_out, test_attr.ctx_size_out);
1445 if (err)
1446 goto free_ctx_in;
1447 }
1448
1449 test_attr.repeat = repeat;
1450 test_attr.data_in = data_in;
1451 test_attr.data_out = data_out;
1452 test_attr.ctx_in = ctx_in;
1453 test_attr.ctx_out = ctx_out;
1454
1455 err = bpf_prog_test_run_opts(fd, &test_attr);
1456 if (err) {
1457 p_err("failed to run program: %s", strerror(errno));
1458 goto free_ctx_out;
1459 }
1460
1461 err = 0;
1462
1463 if (json_output)
1464 jsonw_start_object(json_wtr); /* root */
1465
1466 /* Do not exit on errors occurring when printing output data/context,
1467 * we still want to print return value and duration for program run.
1468 */
1469 if (test_attr.data_size_out)
1470 err += print_run_output(test_attr.data_out,
1471 test_attr.data_size_out,
1472 data_fname_out, "data_out");
1473 if (test_attr.ctx_size_out)
1474 err += print_run_output(test_attr.ctx_out,
1475 test_attr.ctx_size_out,
1476 ctx_fname_out, "ctx_out");
1477
1478 if (json_output) {
1479 jsonw_uint_field(json_wtr, "retval", test_attr.retval);
1480 jsonw_uint_field(json_wtr, "duration", test_attr.duration);
1481 jsonw_end_object(json_wtr); /* root */
1482 } else {
1483 fprintf(stdout, "Return value: %u, duration%s: %uns\n",
1484 test_attr.retval,
1485 repeat > 1 ? " (average)" : "", test_attr.duration);
1486 }
1487
1488free_ctx_out:
1489 free(ctx_out);
1490free_ctx_in:
1491 free(ctx_in);
1492free_data_out:
1493 free(data_out);
1494free_data_in:
1495 free(data_in);
1496
1497 return err;
1498}
1499
1500static int
1501get_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
1502 enum bpf_attach_type *expected_attach_type)
1503{
1504 libbpf_print_fn_t print_backup;
1505 int ret;
1506
1507 ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type);
1508 if (!ret)
1509 return ret;
1510
1511 /* libbpf_prog_type_by_name() failed, let's re-run with debug level */
1512 print_backup = libbpf_set_print(print_all_levels);
1513 ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type);
1514 libbpf_set_print(print_backup);
1515
1516 return ret;
1517}
1518
1519static int
1520auto_attach_program(struct bpf_program *prog, const char *path)
1521{
1522 struct bpf_link *link;
1523 int err;
1524
1525 link = bpf_program__attach(prog);
1526 if (!link) {
1527 p_info("Program %s does not support autoattach, falling back to pinning",
1528 bpf_program__name(prog));
1529 return bpf_obj_pin(bpf_program__fd(prog), path);
1530 }
1531
1532 err = bpf_link__pin(link, path);
1533 bpf_link__destroy(link);
1534 return err;
1535}
1536
1537static int
1538auto_attach_programs(struct bpf_object *obj, const char *path)
1539{
1540 struct bpf_program *prog;
1541 char buf[PATH_MAX];
1542 int err;
1543
1544 bpf_object__for_each_program(prog, obj) {
1545 err = pathname_concat(buf, sizeof(buf), path, bpf_program__name(prog));
1546 if (err)
1547 goto err_unpin_programs;
1548
1549 err = auto_attach_program(prog, buf);
1550 if (err)
1551 goto err_unpin_programs;
1552 }
1553
1554 return 0;
1555
1556err_unpin_programs:
1557 while ((prog = bpf_object__prev_program(obj, prog))) {
1558 if (pathname_concat(buf, sizeof(buf), path, bpf_program__name(prog)))
1559 continue;
1560
1561 bpf_program__unpin(prog, buf);
1562 }
1563
1564 return err;
1565}
1566
1567static int load_with_options(int argc, char **argv, bool first_prog_only)
1568{
1569 enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC;
1570 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts,
1571 .relaxed_maps = relaxed_maps,
1572 );
1573 enum bpf_attach_type expected_attach_type;
1574 struct map_replace *map_replace = NULL;
1575 struct bpf_program *prog = NULL, *pos;
1576 unsigned int old_map_fds = 0;
1577 const char *pinmaps = NULL;
1578 __u32 xdpmeta_ifindex = 0;
1579 __u32 offload_ifindex = 0;
1580 bool auto_attach = false;
1581 struct bpf_object *obj;
1582 struct bpf_map *map;
1583 const char *pinfile;
1584 unsigned int i, j;
1585 const char *file;
1586 int idx, err;
1587
1588
1589 if (!REQ_ARGS(2))
1590 return -1;
1591 file = GET_ARG();
1592 pinfile = GET_ARG();
1593
1594 while (argc) {
1595 if (is_prefix(*argv, "type")) {
1596 NEXT_ARG();
1597
1598 if (common_prog_type != BPF_PROG_TYPE_UNSPEC) {
1599 p_err("program type already specified");
1600 goto err_free_reuse_maps;
1601 }
1602 if (!REQ_ARGS(1))
1603 goto err_free_reuse_maps;
1604
1605 err = libbpf_prog_type_by_name(*argv, &common_prog_type,
1606 &expected_attach_type);
1607 if (err < 0) {
1608 /* Put a '/' at the end of type to appease libbpf */
1609 char *type = malloc(strlen(*argv) + 2);
1610
1611 if (!type) {
1612 p_err("mem alloc failed");
1613 goto err_free_reuse_maps;
1614 }
1615 *type = 0;
1616 strcat(type, *argv);
1617 strcat(type, "/");
1618
1619 err = get_prog_type_by_name(type, &common_prog_type,
1620 &expected_attach_type);
1621 free(type);
1622 if (err < 0)
1623 goto err_free_reuse_maps;
1624 }
1625
1626 NEXT_ARG();
1627 } else if (is_prefix(*argv, "map")) {
1628 void *new_map_replace;
1629 char *endptr, *name;
1630 int fd;
1631
1632 NEXT_ARG();
1633
1634 if (!REQ_ARGS(4))
1635 goto err_free_reuse_maps;
1636
1637 if (is_prefix(*argv, "idx")) {
1638 NEXT_ARG();
1639
1640 idx = strtoul(*argv, &endptr, 0);
1641 if (*endptr) {
1642 p_err("can't parse %s as IDX", *argv);
1643 goto err_free_reuse_maps;
1644 }
1645 name = NULL;
1646 } else if (is_prefix(*argv, "name")) {
1647 NEXT_ARG();
1648
1649 name = *argv;
1650 idx = -1;
1651 } else {
1652 p_err("expected 'idx' or 'name', got: '%s'?",
1653 *argv);
1654 goto err_free_reuse_maps;
1655 }
1656 NEXT_ARG();
1657
1658 fd = map_parse_fd(&argc, &argv, 0);
1659 if (fd < 0)
1660 goto err_free_reuse_maps;
1661
1662 new_map_replace = libbpf_reallocarray(map_replace,
1663 old_map_fds + 1,
1664 sizeof(*map_replace));
1665 if (!new_map_replace) {
1666 p_err("mem alloc failed");
1667 goto err_free_reuse_maps;
1668 }
1669 map_replace = new_map_replace;
1670
1671 map_replace[old_map_fds].idx = idx;
1672 map_replace[old_map_fds].name = name;
1673 map_replace[old_map_fds].fd = fd;
1674 old_map_fds++;
1675 } else if (is_prefix(*argv, "dev")) {
1676 p_info("Warning: 'bpftool prog load [...] dev <ifname>' syntax is deprecated.\n"
1677 "Going further, please use 'offload_dev <ifname>' to offload program to device.\n"
1678 "For applications using XDP hints only, use 'xdpmeta_dev <ifname>'.");
1679 goto offload_dev;
1680 } else if (is_prefix(*argv, "offload_dev")) {
1681offload_dev:
1682 NEXT_ARG();
1683
1684 if (offload_ifindex) {
1685 p_err("offload_dev already specified");
1686 goto err_free_reuse_maps;
1687 } else if (xdpmeta_ifindex) {
1688 p_err("xdpmeta_dev and offload_dev are mutually exclusive");
1689 goto err_free_reuse_maps;
1690 }
1691 if (!REQ_ARGS(1))
1692 goto err_free_reuse_maps;
1693
1694 offload_ifindex = if_nametoindex(*argv);
1695 if (!offload_ifindex) {
1696 p_err("unrecognized netdevice '%s': %s",
1697 *argv, strerror(errno));
1698 goto err_free_reuse_maps;
1699 }
1700 NEXT_ARG();
1701 } else if (is_prefix(*argv, "xdpmeta_dev")) {
1702 NEXT_ARG();
1703
1704 if (xdpmeta_ifindex) {
1705 p_err("xdpmeta_dev already specified");
1706 goto err_free_reuse_maps;
1707 } else if (offload_ifindex) {
1708 p_err("xdpmeta_dev and offload_dev are mutually exclusive");
1709 goto err_free_reuse_maps;
1710 }
1711 if (!REQ_ARGS(1))
1712 goto err_free_reuse_maps;
1713
1714 xdpmeta_ifindex = if_nametoindex(*argv);
1715 if (!xdpmeta_ifindex) {
1716 p_err("unrecognized netdevice '%s': %s",
1717 *argv, strerror(errno));
1718 goto err_free_reuse_maps;
1719 }
1720 NEXT_ARG();
1721 } else if (is_prefix(*argv, "pinmaps")) {
1722 NEXT_ARG();
1723
1724 if (!REQ_ARGS(1))
1725 goto err_free_reuse_maps;
1726
1727 pinmaps = GET_ARG();
1728 } else if (is_prefix(*argv, "autoattach")) {
1729 auto_attach = true;
1730 NEXT_ARG();
1731 } else if (is_prefix(*argv, "kernel_btf")) {
1732 NEXT_ARG();
1733
1734 if (!REQ_ARGS(1))
1735 goto err_free_reuse_maps;
1736
1737 open_opts.btf_custom_path = GET_ARG();
1738 } else {
1739 p_err("expected no more arguments, "
1740 "'type', 'map', 'offload_dev', 'xdpmeta_dev', 'pinmaps', "
1741 "'autoattach', or 'kernel_btf', got: '%s'?",
1742 *argv);
1743 goto err_free_reuse_maps;
1744 }
1745 }
1746
1747 set_max_rlimit();
1748
1749 if (verifier_logs)
1750 /* log_level1 + log_level2 + stats, but not stable UAPI */
1751 open_opts.kernel_log_level = 1 + 2 + 4;
1752
1753 obj = bpf_object__open_file(file, &open_opts);
1754 if (!obj) {
1755 p_err("failed to open object file");
1756 goto err_free_reuse_maps;
1757 }
1758
1759 bpf_object__for_each_program(pos, obj) {
1760 enum bpf_prog_type prog_type = common_prog_type;
1761
1762 if (prog_type == BPF_PROG_TYPE_UNSPEC) {
1763 const char *sec_name = bpf_program__section_name(pos);
1764
1765 err = get_prog_type_by_name(sec_name, &prog_type,
1766 &expected_attach_type);
1767 if (err < 0)
1768 goto err_close_obj;
1769 }
1770
1771 if (prog_type == BPF_PROG_TYPE_XDP && xdpmeta_ifindex) {
1772 bpf_program__set_flags(pos, BPF_F_XDP_DEV_BOUND_ONLY);
1773 bpf_program__set_ifindex(pos, xdpmeta_ifindex);
1774 } else {
1775 bpf_program__set_ifindex(pos, offload_ifindex);
1776 }
1777 if (bpf_program__type(pos) != prog_type)
1778 bpf_program__set_type(pos, prog_type);
1779 bpf_program__set_expected_attach_type(pos, expected_attach_type);
1780 }
1781
1782 qsort(map_replace, old_map_fds, sizeof(*map_replace),
1783 map_replace_compar);
1784
1785 /* After the sort maps by name will be first on the list, because they
1786 * have idx == -1. Resolve them.
1787 */
1788 j = 0;
1789 while (j < old_map_fds && map_replace[j].name) {
1790 i = 0;
1791 bpf_object__for_each_map(map, obj) {
1792 if (!strcmp(bpf_map__name(map), map_replace[j].name)) {
1793 map_replace[j].idx = i;
1794 break;
1795 }
1796 i++;
1797 }
1798 if (map_replace[j].idx == -1) {
1799 p_err("unable to find map '%s'", map_replace[j].name);
1800 goto err_close_obj;
1801 }
1802 j++;
1803 }
1804 /* Resort if any names were resolved */
1805 if (j)
1806 qsort(map_replace, old_map_fds, sizeof(*map_replace),
1807 map_replace_compar);
1808
1809 /* Set ifindex and name reuse */
1810 j = 0;
1811 idx = 0;
1812 bpf_object__for_each_map(map, obj) {
1813 if (bpf_map__type(map) != BPF_MAP_TYPE_PERF_EVENT_ARRAY)
1814 bpf_map__set_ifindex(map, offload_ifindex);
1815
1816 if (j < old_map_fds && idx == map_replace[j].idx) {
1817 err = bpf_map__reuse_fd(map, map_replace[j++].fd);
1818 if (err) {
1819 p_err("unable to set up map reuse: %d", err);
1820 goto err_close_obj;
1821 }
1822
1823 /* Next reuse wants to apply to the same map */
1824 if (j < old_map_fds && map_replace[j].idx == idx) {
1825 p_err("replacement for map idx %d specified more than once",
1826 idx);
1827 goto err_close_obj;
1828 }
1829 }
1830
1831 idx++;
1832 }
1833 if (j < old_map_fds) {
1834 p_err("map idx '%d' not used", map_replace[j].idx);
1835 goto err_close_obj;
1836 }
1837
1838 err = bpf_object__load(obj);
1839 if (err) {
1840 p_err("failed to load object file");
1841 goto err_close_obj;
1842 }
1843
1844 if (first_prog_only)
1845 err = mount_bpffs_for_file(pinfile);
1846 else
1847 err = create_and_mount_bpffs_dir(pinfile);
1848 if (err)
1849 goto err_close_obj;
1850
1851 if (first_prog_only) {
1852 prog = bpf_object__next_program(obj, NULL);
1853 if (!prog) {
1854 p_err("object file doesn't contain any bpf program");
1855 goto err_close_obj;
1856 }
1857
1858 if (auto_attach)
1859 err = auto_attach_program(prog, pinfile);
1860 else
1861 err = bpf_obj_pin(bpf_program__fd(prog), pinfile);
1862 if (err) {
1863 p_err("failed to pin program %s",
1864 bpf_program__section_name(prog));
1865 goto err_close_obj;
1866 }
1867 } else {
1868 if (auto_attach)
1869 err = auto_attach_programs(obj, pinfile);
1870 else
1871 err = bpf_object__pin_programs(obj, pinfile);
1872 if (err) {
1873 p_err("failed to pin all programs");
1874 goto err_close_obj;
1875 }
1876 }
1877
1878 if (pinmaps) {
1879 err = create_and_mount_bpffs_dir(pinmaps);
1880 if (err)
1881 goto err_unpin;
1882
1883 err = bpf_object__pin_maps(obj, pinmaps);
1884 if (err) {
1885 p_err("failed to pin all maps");
1886 goto err_unpin;
1887 }
1888 }
1889
1890 if (json_output)
1891 jsonw_null(json_wtr);
1892
1893 bpf_object__close(obj);
1894 for (i = 0; i < old_map_fds; i++)
1895 close(map_replace[i].fd);
1896 free(map_replace);
1897
1898 return 0;
1899
1900err_unpin:
1901 if (first_prog_only)
1902 unlink(pinfile);
1903 else
1904 bpf_object__unpin_programs(obj, pinfile);
1905err_close_obj:
1906 bpf_object__close(obj);
1907err_free_reuse_maps:
1908 for (i = 0; i < old_map_fds; i++)
1909 close(map_replace[i].fd);
1910 free(map_replace);
1911 return -1;
1912}
1913
1914static int count_open_fds(void)
1915{
1916 DIR *dp = opendir("/proc/self/fd");
1917 struct dirent *de;
1918 int cnt = -3;
1919
1920 if (!dp)
1921 return -1;
1922
1923 while ((de = readdir(dp)))
1924 cnt++;
1925
1926 closedir(dp);
1927 return cnt;
1928}
1929
1930static int try_loader(struct gen_loader_opts *gen)
1931{
1932 struct bpf_load_and_run_opts opts = {};
1933 struct bpf_loader_ctx *ctx;
1934 char sig_buf[MAX_SIG_SIZE];
1935 __u8 prog_sha[SHA256_DIGEST_LENGTH];
1936 int ctx_sz = sizeof(*ctx) + 64 * max(sizeof(struct bpf_map_desc),
1937 sizeof(struct bpf_prog_desc));
1938 int log_buf_sz = (1u << 24) - 1;
1939 int err, fds_before, fd_delta;
1940 char *log_buf = NULL;
1941
1942 ctx = alloca(ctx_sz);
1943 memset(ctx, 0, ctx_sz);
1944 ctx->sz = ctx_sz;
1945 if (verifier_logs) {
1946 ctx->log_level = 1 + 2 + 4;
1947 ctx->log_size = log_buf_sz;
1948 log_buf = malloc(log_buf_sz);
1949 if (!log_buf)
1950 return -ENOMEM;
1951 ctx->log_buf = (long) log_buf;
1952 }
1953 opts.ctx = ctx;
1954 opts.data = gen->data;
1955 opts.data_sz = gen->data_sz;
1956 opts.insns = gen->insns;
1957 opts.insns_sz = gen->insns_sz;
1958 fds_before = count_open_fds();
1959
1960 if (sign_progs) {
1961 opts.excl_prog_hash = prog_sha;
1962 opts.excl_prog_hash_sz = sizeof(prog_sha);
1963 opts.signature = sig_buf;
1964 opts.signature_sz = MAX_SIG_SIZE;
1965 opts.keyring_id = KEY_SPEC_SESSION_KEYRING;
1966
1967 err = bpftool_prog_sign(&opts);
1968 if (err < 0) {
1969 p_err("failed to sign program");
1970 goto out;
1971 }
1972
1973 err = register_session_key(cert_path);
1974 if (err < 0) {
1975 p_err("failed to add session key");
1976 goto out;
1977 }
1978 }
1979 err = bpf_load_and_run(&opts);
1980 fd_delta = count_open_fds() - fds_before;
1981 if (err < 0 || verifier_logs) {
1982 fprintf(stderr, "err %d\n%s\n%s", err, opts.errstr, log_buf);
1983 if (fd_delta && err < 0)
1984 fprintf(stderr, "loader prog leaked %d FDs\n",
1985 fd_delta);
1986 }
1987out:
1988 free(log_buf);
1989 return err;
1990}
1991
1992static int do_loader(int argc, char **argv)
1993{
1994 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts);
1995 DECLARE_LIBBPF_OPTS(gen_loader_opts, gen);
1996 struct bpf_object *obj;
1997 const char *file;
1998 int err = 0;
1999
2000 if (!REQ_ARGS(1))
2001 return -1;
2002 file = GET_ARG();
2003
2004 if (verifier_logs)
2005 /* log_level1 + log_level2 + stats, but not stable UAPI */
2006 open_opts.kernel_log_level = 1 + 2 + 4;
2007
2008 obj = bpf_object__open_file(file, &open_opts);
2009 if (!obj) {
2010 err = -1;
2011 p_err("failed to open object file");
2012 goto err_close_obj;
2013 }
2014
2015 if (sign_progs)
2016 gen.gen_hash = true;
2017
2018 err = bpf_object__gen_loader(obj, &gen);
2019 if (err)
2020 goto err_close_obj;
2021
2022 err = bpf_object__load(obj);
2023 if (err) {
2024 p_err("failed to load object file");
2025 goto err_close_obj;
2026 }
2027
2028 if (verifier_logs) {
2029 struct dump_data dd = {};
2030
2031 kernel_syms_load(&dd);
2032 dump_xlated_plain(&dd, (void *)gen.insns, gen.insns_sz, false, false);
2033 kernel_syms_destroy(&dd);
2034 }
2035 err = try_loader(&gen);
2036err_close_obj:
2037 bpf_object__close(obj);
2038 return err;
2039}
2040
2041static int do_load(int argc, char **argv)
2042{
2043 if (use_loader)
2044 return do_loader(argc, argv);
2045 return load_with_options(argc, argv, true);
2046}
2047
2048static int do_loadall(int argc, char **argv)
2049{
2050 return load_with_options(argc, argv, false);
2051}
2052
2053#ifdef BPFTOOL_WITHOUT_SKELETONS
2054
2055static int do_profile(int argc, char **argv)
2056{
2057 p_err("bpftool prog profile command is not supported. Please build bpftool with clang >= 10.0.0");
2058 return 0;
2059}
2060
2061#else /* BPFTOOL_WITHOUT_SKELETONS */
2062
2063#include "profiler.skel.h"
2064
2065struct profile_metric {
2066 const char *name;
2067 struct bpf_perf_event_value val;
2068 struct perf_event_attr attr;
2069 bool selected;
2070
2071 /* calculate ratios like instructions per cycle */
2072 const int ratio_metric; /* 0 for N/A, 1 for index 0 (cycles) */
2073 const char *ratio_desc;
2074 const float ratio_mul;
2075} metrics[] = {
2076 {
2077 .name = "cycles",
2078 .attr = {
2079 .type = PERF_TYPE_HARDWARE,
2080 .config = PERF_COUNT_HW_CPU_CYCLES,
2081 .exclude_user = 1,
2082 },
2083 },
2084 {
2085 .name = "instructions",
2086 .attr = {
2087 .type = PERF_TYPE_HARDWARE,
2088 .config = PERF_COUNT_HW_INSTRUCTIONS,
2089 .exclude_user = 1,
2090 },
2091 .ratio_metric = 1,
2092 .ratio_desc = "insns per cycle",
2093 .ratio_mul = 1.0,
2094 },
2095 {
2096 .name = "l1d_loads",
2097 .attr = {
2098 .type = PERF_TYPE_HW_CACHE,
2099 .config =
2100 PERF_COUNT_HW_CACHE_L1D |
2101 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
2102 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16),
2103 .exclude_user = 1,
2104 },
2105 },
2106 {
2107 .name = "llc_misses",
2108 .attr = {
2109 .type = PERF_TYPE_HW_CACHE,
2110 .config =
2111 PERF_COUNT_HW_CACHE_LL |
2112 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
2113 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
2114 .exclude_user = 1
2115 },
2116 .ratio_metric = 2,
2117 .ratio_desc = "LLC misses per million insns",
2118 .ratio_mul = 1e6,
2119 },
2120 {
2121 .name = "itlb_misses",
2122 .attr = {
2123 .type = PERF_TYPE_HW_CACHE,
2124 .config =
2125 PERF_COUNT_HW_CACHE_ITLB |
2126 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
2127 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
2128 .exclude_user = 1
2129 },
2130 .ratio_metric = 2,
2131 .ratio_desc = "itlb misses per million insns",
2132 .ratio_mul = 1e6,
2133 },
2134 {
2135 .name = "dtlb_misses",
2136 .attr = {
2137 .type = PERF_TYPE_HW_CACHE,
2138 .config =
2139 PERF_COUNT_HW_CACHE_DTLB |
2140 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
2141 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
2142 .exclude_user = 1
2143 },
2144 .ratio_metric = 2,
2145 .ratio_desc = "dtlb misses per million insns",
2146 .ratio_mul = 1e6,
2147 },
2148};
2149
2150static __u64 profile_total_count;
2151
2152#define MAX_NUM_PROFILE_METRICS 4
2153
2154static int profile_parse_metrics(int argc, char **argv)
2155{
2156 unsigned int metric_cnt;
2157 int selected_cnt = 0;
2158 unsigned int i;
2159
2160 metric_cnt = ARRAY_SIZE(metrics);
2161
2162 while (argc > 0) {
2163 for (i = 0; i < metric_cnt; i++) {
2164 if (is_prefix(argv[0], metrics[i].name)) {
2165 if (!metrics[i].selected)
2166 selected_cnt++;
2167 metrics[i].selected = true;
2168 break;
2169 }
2170 }
2171 if (i == metric_cnt) {
2172 p_err("unknown metric %s", argv[0]);
2173 return -1;
2174 }
2175 NEXT_ARG();
2176 }
2177 if (selected_cnt > MAX_NUM_PROFILE_METRICS) {
2178 p_err("too many (%d) metrics, please specify no more than %d metrics at a time",
2179 selected_cnt, MAX_NUM_PROFILE_METRICS);
2180 return -1;
2181 }
2182 return selected_cnt;
2183}
2184
2185static void profile_read_values(struct profiler_bpf *obj)
2186{
2187 __u32 m, cpu, num_cpu = obj->rodata->num_cpu;
2188 int reading_map_fd, count_map_fd;
2189 __u64 counts[num_cpu];
2190 __u32 key = 0;
2191 int err;
2192
2193 reading_map_fd = bpf_map__fd(obj->maps.accum_readings);
2194 count_map_fd = bpf_map__fd(obj->maps.counts);
2195 if (reading_map_fd < 0 || count_map_fd < 0) {
2196 p_err("failed to get fd for map");
2197 return;
2198 }
2199
2200 err = bpf_map_lookup_elem(count_map_fd, &key, counts);
2201 if (err) {
2202 p_err("failed to read count_map: %s", strerror(errno));
2203 return;
2204 }
2205
2206 profile_total_count = 0;
2207 for (cpu = 0; cpu < num_cpu; cpu++)
2208 profile_total_count += counts[cpu];
2209
2210 for (m = 0; m < ARRAY_SIZE(metrics); m++) {
2211 struct bpf_perf_event_value values[num_cpu];
2212
2213 if (!metrics[m].selected)
2214 continue;
2215
2216 err = bpf_map_lookup_elem(reading_map_fd, &key, values);
2217 if (err) {
2218 p_err("failed to read reading_map: %s",
2219 strerror(errno));
2220 return;
2221 }
2222 for (cpu = 0; cpu < num_cpu; cpu++) {
2223 metrics[m].val.counter += values[cpu].counter;
2224 metrics[m].val.enabled += values[cpu].enabled;
2225 metrics[m].val.running += values[cpu].running;
2226 }
2227 key++;
2228 }
2229}
2230
2231static void profile_print_readings_json(void)
2232{
2233 __u32 m;
2234
2235 jsonw_start_array(json_wtr);
2236 for (m = 0; m < ARRAY_SIZE(metrics); m++) {
2237 if (!metrics[m].selected)
2238 continue;
2239 jsonw_start_object(json_wtr);
2240 jsonw_string_field(json_wtr, "metric", metrics[m].name);
2241 jsonw_lluint_field(json_wtr, "run_cnt", profile_total_count);
2242 jsonw_lluint_field(json_wtr, "value", metrics[m].val.counter);
2243 jsonw_lluint_field(json_wtr, "enabled", metrics[m].val.enabled);
2244 jsonw_lluint_field(json_wtr, "running", metrics[m].val.running);
2245
2246 jsonw_end_object(json_wtr);
2247 }
2248 jsonw_end_array(json_wtr);
2249}
2250
2251static void profile_print_readings_plain(void)
2252{
2253 __u32 m;
2254
2255 printf("\n%18llu %-20s\n", profile_total_count, "run_cnt");
2256 for (m = 0; m < ARRAY_SIZE(metrics); m++) {
2257 struct bpf_perf_event_value *val = &metrics[m].val;
2258 int r;
2259
2260 if (!metrics[m].selected)
2261 continue;
2262 printf("%18llu %-20s", val->counter, metrics[m].name);
2263
2264 r = metrics[m].ratio_metric - 1;
2265 if (r >= 0 && metrics[r].selected &&
2266 metrics[r].val.counter > 0) {
2267 printf("# %8.2f %-30s",
2268 val->counter * metrics[m].ratio_mul /
2269 metrics[r].val.counter,
2270 metrics[m].ratio_desc);
2271 } else {
2272 printf("%-41s", "");
2273 }
2274
2275 if (val->enabled > val->running)
2276 printf("(%4.2f%%)",
2277 val->running * 100.0 / val->enabled);
2278 printf("\n");
2279 }
2280}
2281
2282static void profile_print_readings(void)
2283{
2284 if (json_output)
2285 profile_print_readings_json();
2286 else
2287 profile_print_readings_plain();
2288}
2289
2290static char *profile_target_name(int tgt_fd)
2291{
2292 struct bpf_func_info func_info = {};
2293 struct bpf_prog_info info = {};
2294 __u32 info_len = sizeof(info);
2295 const struct btf_type *t;
2296 __u32 func_info_rec_size;
2297 struct btf *btf = NULL;
2298 char *name = NULL;
2299 int err;
2300
2301 err = bpf_prog_get_info_by_fd(tgt_fd, &info, &info_len);
2302 if (err) {
2303 p_err("failed to get info for prog FD %d", tgt_fd);
2304 goto out;
2305 }
2306
2307 if (info.btf_id == 0) {
2308 p_err("prog FD %d doesn't have valid btf", tgt_fd);
2309 goto out;
2310 }
2311
2312 func_info_rec_size = info.func_info_rec_size;
2313 if (info.nr_func_info == 0) {
2314 p_err("found 0 func_info for prog FD %d", tgt_fd);
2315 goto out;
2316 }
2317
2318 memset(&info, 0, sizeof(info));
2319 info.nr_func_info = 1;
2320 info.func_info_rec_size = func_info_rec_size;
2321 info.func_info = ptr_to_u64(&func_info);
2322
2323 err = bpf_prog_get_info_by_fd(tgt_fd, &info, &info_len);
2324 if (err) {
2325 p_err("failed to get func_info for prog FD %d", tgt_fd);
2326 goto out;
2327 }
2328
2329 btf = btf__load_from_kernel_by_id(info.btf_id);
2330 if (!btf) {
2331 p_err("failed to load btf for prog FD %d", tgt_fd);
2332 goto out;
2333 }
2334
2335 t = btf__type_by_id(btf, func_info.type_id);
2336 if (!t) {
2337 p_err("btf %u doesn't have type %u",
2338 info.btf_id, func_info.type_id);
2339 goto out;
2340 }
2341 name = strdup(btf__name_by_offset(btf, t->name_off));
2342out:
2343 btf__free(btf);
2344 return name;
2345}
2346
2347static struct profiler_bpf *profile_obj;
2348static int profile_tgt_fd = -1;
2349static char *profile_tgt_name;
2350static int *profile_perf_events;
2351static int profile_perf_event_cnt;
2352
2353static void profile_close_perf_events(struct profiler_bpf *obj)
2354{
2355 int i;
2356
2357 for (i = profile_perf_event_cnt - 1; i >= 0; i--)
2358 close(profile_perf_events[i]);
2359
2360 free(profile_perf_events);
2361 profile_perf_event_cnt = 0;
2362}
2363
2364static int profile_open_perf_event(int mid, int cpu, int map_fd)
2365{
2366 int pmu_fd;
2367
2368 pmu_fd = syscall(__NR_perf_event_open, &metrics[mid].attr,
2369 -1 /*pid*/, cpu, -1 /*group_fd*/, 0);
2370 if (pmu_fd < 0) {
2371 if (errno == ENODEV) {
2372 p_info("cpu %d may be offline, skip %s profiling.",
2373 cpu, metrics[mid].name);
2374 profile_perf_event_cnt++;
2375 return 0;
2376 }
2377 return -1;
2378 }
2379
2380 if (bpf_map_update_elem(map_fd,
2381 &profile_perf_event_cnt,
2382 &pmu_fd, BPF_ANY) ||
2383 ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0)) {
2384 close(pmu_fd);
2385 return -1;
2386 }
2387
2388 profile_perf_events[profile_perf_event_cnt++] = pmu_fd;
2389 return 0;
2390}
2391
2392static int profile_open_perf_events(struct profiler_bpf *obj)
2393{
2394 unsigned int cpu, m;
2395 int map_fd;
2396
2397 profile_perf_events = calloc(
2398 obj->rodata->num_cpu * obj->rodata->num_metric, sizeof(int));
2399 if (!profile_perf_events) {
2400 p_err("failed to allocate memory for perf_event array: %s",
2401 strerror(errno));
2402 return -1;
2403 }
2404 map_fd = bpf_map__fd(obj->maps.events);
2405 if (map_fd < 0) {
2406 p_err("failed to get fd for events map");
2407 return -1;
2408 }
2409
2410 for (m = 0; m < ARRAY_SIZE(metrics); m++) {
2411 if (!metrics[m].selected)
2412 continue;
2413 for (cpu = 0; cpu < obj->rodata->num_cpu; cpu++) {
2414 if (profile_open_perf_event(m, cpu, map_fd)) {
2415 p_err("failed to create event %s on cpu %u",
2416 metrics[m].name, cpu);
2417 return -1;
2418 }
2419 }
2420 }
2421 return 0;
2422}
2423
2424static void profile_print_and_cleanup(void)
2425{
2426 profile_close_perf_events(profile_obj);
2427 profile_read_values(profile_obj);
2428 profile_print_readings();
2429 profiler_bpf__destroy(profile_obj);
2430
2431 close(profile_tgt_fd);
2432 free(profile_tgt_name);
2433}
2434
2435static void int_exit(int signo)
2436{
2437 profile_print_and_cleanup();
2438 exit(0);
2439}
2440
2441static int do_profile(int argc, char **argv)
2442{
2443 int num_metric, num_cpu, err = -1;
2444 struct bpf_program *prog;
2445 unsigned long duration;
2446 char *endptr;
2447
2448 /* we at least need two args for the prog and one metric */
2449 if (!REQ_ARGS(3))
2450 return -EINVAL;
2451
2452 /* parse target fd */
2453 profile_tgt_fd = prog_parse_fd(&argc, &argv);
2454 if (profile_tgt_fd < 0) {
2455 p_err("failed to parse fd");
2456 return -1;
2457 }
2458
2459 /* parse profiling optional duration */
2460 if (argc > 2 && is_prefix(argv[0], "duration")) {
2461 NEXT_ARG();
2462 duration = strtoul(*argv, &endptr, 0);
2463 if (*endptr)
2464 usage();
2465 NEXT_ARG();
2466 } else {
2467 duration = UINT_MAX;
2468 }
2469
2470 num_metric = profile_parse_metrics(argc, argv);
2471 if (num_metric <= 0)
2472 goto out;
2473
2474 num_cpu = libbpf_num_possible_cpus();
2475 if (num_cpu <= 0) {
2476 p_err("failed to identify number of CPUs");
2477 goto out;
2478 }
2479
2480 profile_obj = profiler_bpf__open();
2481 if (!profile_obj) {
2482 p_err("failed to open and/or load BPF object");
2483 goto out;
2484 }
2485
2486 profile_obj->rodata->num_cpu = num_cpu;
2487 profile_obj->rodata->num_metric = num_metric;
2488
2489 /* adjust map sizes */
2490 bpf_map__set_max_entries(profile_obj->maps.events, num_metric * num_cpu);
2491 bpf_map__set_max_entries(profile_obj->maps.fentry_readings, num_metric);
2492 bpf_map__set_max_entries(profile_obj->maps.accum_readings, num_metric);
2493 bpf_map__set_max_entries(profile_obj->maps.counts, 1);
2494
2495 /* change target name */
2496 profile_tgt_name = profile_target_name(profile_tgt_fd);
2497 if (!profile_tgt_name)
2498 goto out;
2499
2500 bpf_object__for_each_program(prog, profile_obj->obj) {
2501 err = bpf_program__set_attach_target(prog, profile_tgt_fd,
2502 profile_tgt_name);
2503 if (err) {
2504 p_err("failed to set attach target\n");
2505 goto out;
2506 }
2507 }
2508
2509 set_max_rlimit();
2510 err = profiler_bpf__load(profile_obj);
2511 if (err) {
2512 p_err("failed to load profile_obj");
2513 goto out;
2514 }
2515
2516 err = profile_open_perf_events(profile_obj);
2517 if (err)
2518 goto out;
2519
2520 err = profiler_bpf__attach(profile_obj);
2521 if (err) {
2522 p_err("failed to attach profile_obj");
2523 goto out;
2524 }
2525 signal(SIGINT, int_exit);
2526
2527 sleep(duration);
2528 profile_print_and_cleanup();
2529 return 0;
2530
2531out:
2532 profile_close_perf_events(profile_obj);
2533 if (profile_obj)
2534 profiler_bpf__destroy(profile_obj);
2535 close(profile_tgt_fd);
2536 free(profile_tgt_name);
2537 return err;
2538}
2539
2540#endif /* BPFTOOL_WITHOUT_SKELETONS */
2541
2542static int do_help(int argc, char **argv)
2543{
2544 if (json_output) {
2545 jsonw_null(json_wtr);
2546 return 0;
2547 }
2548
2549 fprintf(stderr,
2550 "Usage: %1$s %2$s { show | list } [PROG]\n"
2551 " %1$s %2$s dump xlated PROG [{ file FILE | [opcodes] [linum] [visual] }]\n"
2552 " %1$s %2$s dump jited PROG [{ file FILE | [opcodes] [linum] }]\n"
2553 " %1$s %2$s pin PROG FILE\n"
2554 " %1$s %2$s { load | loadall } OBJ PATH \\\n"
2555 " [type TYPE] [{ offload_dev | xdpmeta_dev } NAME] \\\n"
2556 " [map { idx IDX | name NAME } MAP]\\\n"
2557 " [pinmaps MAP_DIR]\n"
2558 " [autoattach]\n"
2559 " [kernel_btf BTF_FILE]\n"
2560 " %1$s %2$s attach PROG ATTACH_TYPE [MAP]\n"
2561 " %1$s %2$s detach PROG ATTACH_TYPE [MAP]\n"
2562 " %1$s %2$s run PROG \\\n"
2563 " data_in FILE \\\n"
2564 " [data_out FILE [data_size_out L]] \\\n"
2565 " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n"
2566 " [repeat N]\n"
2567 " %1$s %2$s profile PROG [duration DURATION] METRICs\n"
2568 " %1$s %2$s tracelog\n"
2569 " %1$s %2$s tracelog { stdout | stderr } PROG\n"
2570 " %1$s %2$s help\n"
2571 "\n"
2572 " " HELP_SPEC_MAP "\n"
2573 " " HELP_SPEC_PROGRAM "\n"
2574 " TYPE := { socket | kprobe | kretprobe | classifier | action |\n"
2575 " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n"
2576 " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n"
2577 " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n"
2578 " sk_reuseport | flow_dissector | cgroup/sysctl |\n"
2579 " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n"
2580 " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n"
2581 " cgroup/connect_unix | cgroup/getpeername4 | cgroup/getpeername6 |\n"
2582 " cgroup/getpeername_unix | cgroup/getsockname4 | cgroup/getsockname6 |\n"
2583 " cgroup/getsockname_unix | cgroup/sendmsg4 | cgroup/sendmsg6 |\n"
2584 " cgroup/sendmsg_unix | cgroup/recvmsg4 | cgroup/recvmsg6 | cgroup/recvmsg_unix |\n"
2585 " cgroup/getsockopt | cgroup/setsockopt | cgroup/sock_release |\n"
2586 " struct_ops | fentry | fexit | freplace | sk_lookup }\n"
2587 " ATTACH_TYPE := { sk_msg_verdict | sk_skb_verdict | sk_skb_stream_verdict |\n"
2588 " sk_skb_stream_parser | flow_dissector }\n"
2589 " METRIC := { cycles | instructions | l1d_loads | llc_misses | itlb_misses | dtlb_misses }\n"
2590 " " HELP_SPEC_OPTIONS " |\n"
2591 " {-f|--bpffs} | {-m|--mapcompat} | {-n|--nomount} |\n"
2592 " {-L|--use-loader} | [ {-S|--sign } {-k} <private_key.pem> {-i} <certificate.x509> ] \n"
2593 "",
2594 bin_name, argv[-2]);
2595
2596 return 0;
2597}
2598
2599static const struct cmd cmds[] = {
2600 { "show", do_show },
2601 { "list", do_show },
2602 { "help", do_help },
2603 { "dump", do_dump },
2604 { "pin", do_pin },
2605 { "load", do_load },
2606 { "loadall", do_loadall },
2607 { "attach", do_attach },
2608 { "detach", do_detach },
2609 { "tracelog", do_tracelog_any },
2610 { "run", do_run },
2611 { "profile", do_profile },
2612 { 0 }
2613};
2614
2615int do_prog(int argc, char **argv)
2616{
2617 return cmd_select(cmds, argc, argv, do_help);
2618}