Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/shli/md
[sfrench/cifs-2.6.git] / tools / bpf / bpftool / prog.c
1 /*
2  * Copyright (C) 2017 Netronome Systems, Inc.
3  *
4  * This software is dual licensed under the GNU General License Version 2,
5  * June 1991 as shown in the file COPYING in the top-level directory of this
6  * source tree or the BSD 2-Clause License provided below.  You have the
7  * option to license this software under the complete terms of either license.
8  *
9  * The BSD 2-Clause License:
10  *
11  *     Redistribution and use in source and binary forms, with or
12  *     without modification, are permitted provided that the following
13  *     conditions are met:
14  *
15  *      1. Redistributions of source code must retain the above
16  *         copyright notice, this list of conditions and the following
17  *         disclaimer.
18  *
19  *      2. Redistributions in binary form must reproduce the above
20  *         copyright notice, this list of conditions and the following
21  *         disclaimer in the documentation and/or other materials
22  *         provided with the distribution.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31  * SOFTWARE.
32  */
33
34 /* Author: Jakub Kicinski <kubakici@wp.pl> */
35
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <time.h>
43 #include <unistd.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46
47 #include <bpf.h>
48 #include <libbpf.h>
49
50 #include "main.h"
51 #include "disasm.h"
52
53 static const char * const prog_type_name[] = {
54         [BPF_PROG_TYPE_UNSPEC]          = "unspec",
55         [BPF_PROG_TYPE_SOCKET_FILTER]   = "socket_filter",
56         [BPF_PROG_TYPE_KPROBE]          = "kprobe",
57         [BPF_PROG_TYPE_SCHED_CLS]       = "sched_cls",
58         [BPF_PROG_TYPE_SCHED_ACT]       = "sched_act",
59         [BPF_PROG_TYPE_TRACEPOINT]      = "tracepoint",
60         [BPF_PROG_TYPE_XDP]             = "xdp",
61         [BPF_PROG_TYPE_PERF_EVENT]      = "perf_event",
62         [BPF_PROG_TYPE_CGROUP_SKB]      = "cgroup_skb",
63         [BPF_PROG_TYPE_CGROUP_SOCK]     = "cgroup_sock",
64         [BPF_PROG_TYPE_LWT_IN]          = "lwt_in",
65         [BPF_PROG_TYPE_LWT_OUT]         = "lwt_out",
66         [BPF_PROG_TYPE_LWT_XMIT]        = "lwt_xmit",
67         [BPF_PROG_TYPE_SOCK_OPS]        = "sock_ops",
68         [BPF_PROG_TYPE_SK_SKB]          = "sk_skb",
69         [BPF_PROG_TYPE_CGROUP_DEVICE]   = "cgroup_device",
70 };
71
72 static void print_boot_time(__u64 nsecs, char *buf, unsigned int size)
73 {
74         struct timespec real_time_ts, boot_time_ts;
75         time_t wallclock_secs;
76         struct tm load_tm;
77
78         buf[--size] = '\0';
79
80         if (clock_gettime(CLOCK_REALTIME, &real_time_ts) ||
81             clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) {
82                 perror("Can't read clocks");
83                 snprintf(buf, size, "%llu", nsecs / 1000000000);
84                 return;
85         }
86
87         wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) +
88                 nsecs / 1000000000;
89
90         if (!localtime_r(&wallclock_secs, &load_tm)) {
91                 snprintf(buf, size, "%llu", nsecs / 1000000000);
92                 return;
93         }
94
95         strftime(buf, size, "%b %d/%H:%M", &load_tm);
96 }
97
98 static int prog_fd_by_tag(unsigned char *tag)
99 {
100         struct bpf_prog_info info = {};
101         __u32 len = sizeof(info);
102         unsigned int id = 0;
103         int err;
104         int fd;
105
106         while (true) {
107                 err = bpf_prog_get_next_id(id, &id);
108                 if (err) {
109                         p_err("%s", strerror(errno));
110                         return -1;
111                 }
112
113                 fd = bpf_prog_get_fd_by_id(id);
114                 if (fd < 0) {
115                         p_err("can't get prog by id (%u): %s",
116                               id, strerror(errno));
117                         return -1;
118                 }
119
120                 err = bpf_obj_get_info_by_fd(fd, &info, &len);
121                 if (err) {
122                         p_err("can't get prog info (%u): %s",
123                               id, strerror(errno));
124                         close(fd);
125                         return -1;
126                 }
127
128                 if (!memcmp(tag, info.tag, BPF_TAG_SIZE))
129                         return fd;
130
131                 close(fd);
132         }
133 }
134
135 int prog_parse_fd(int *argc, char ***argv)
136 {
137         int fd;
138
139         if (is_prefix(**argv, "id")) {
140                 unsigned int id;
141                 char *endptr;
142
143                 NEXT_ARGP();
144
145                 id = strtoul(**argv, &endptr, 0);
146                 if (*endptr) {
147                         p_err("can't parse %s as ID", **argv);
148                         return -1;
149                 }
150                 NEXT_ARGP();
151
152                 fd = bpf_prog_get_fd_by_id(id);
153                 if (fd < 0)
154                         p_err("get by id (%u): %s", id, strerror(errno));
155                 return fd;
156         } else if (is_prefix(**argv, "tag")) {
157                 unsigned char tag[BPF_TAG_SIZE];
158
159                 NEXT_ARGP();
160
161                 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2,
162                            tag + 3, tag + 4, tag + 5, tag + 6, tag + 7)
163                     != BPF_TAG_SIZE) {
164                         p_err("can't parse tag");
165                         return -1;
166                 }
167                 NEXT_ARGP();
168
169                 return prog_fd_by_tag(tag);
170         } else if (is_prefix(**argv, "pinned")) {
171                 char *path;
172
173                 NEXT_ARGP();
174
175                 path = **argv;
176                 NEXT_ARGP();
177
178                 return open_obj_pinned_any(path, BPF_OBJ_PROG);
179         }
180
181         p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv);
182         return -1;
183 }
184
185 static void show_prog_maps(int fd, u32 num_maps)
186 {
187         struct bpf_prog_info info = {};
188         __u32 len = sizeof(info);
189         __u32 map_ids[num_maps];
190         unsigned int i;
191         int err;
192
193         info.nr_map_ids = num_maps;
194         info.map_ids = ptr_to_u64(map_ids);
195
196         err = bpf_obj_get_info_by_fd(fd, &info, &len);
197         if (err || !info.nr_map_ids)
198                 return;
199
200         if (json_output) {
201                 jsonw_name(json_wtr, "map_ids");
202                 jsonw_start_array(json_wtr);
203                 for (i = 0; i < info.nr_map_ids; i++)
204                         jsonw_uint(json_wtr, map_ids[i]);
205                 jsonw_end_array(json_wtr);
206         } else {
207                 printf("  map_ids ");
208                 for (i = 0; i < info.nr_map_ids; i++)
209                         printf("%u%s", map_ids[i],
210                                i == info.nr_map_ids - 1 ? "" : ",");
211         }
212 }
213
214 static void print_prog_json(struct bpf_prog_info *info, int fd)
215 {
216         char *memlock;
217
218         jsonw_start_object(json_wtr);
219         jsonw_uint_field(json_wtr, "id", info->id);
220         if (info->type < ARRAY_SIZE(prog_type_name))
221                 jsonw_string_field(json_wtr, "type",
222                                    prog_type_name[info->type]);
223         else
224                 jsonw_uint_field(json_wtr, "type", info->type);
225
226         if (*info->name)
227                 jsonw_string_field(json_wtr, "name", info->name);
228
229         jsonw_name(json_wtr, "tag");
230         jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"",
231                      info->tag[0], info->tag[1], info->tag[2], info->tag[3],
232                      info->tag[4], info->tag[5], info->tag[6], info->tag[7]);
233
234         print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
235
236         if (info->load_time) {
237                 char buf[32];
238
239                 print_boot_time(info->load_time, buf, sizeof(buf));
240
241                 /* Piggy back on load_time, since 0 uid is a valid one */
242                 jsonw_string_field(json_wtr, "loaded_at", buf);
243                 jsonw_uint_field(json_wtr, "uid", info->created_by_uid);
244         }
245
246         jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len);
247
248         if (info->jited_prog_len) {
249                 jsonw_bool_field(json_wtr, "jited", true);
250                 jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len);
251         } else {
252                 jsonw_bool_field(json_wtr, "jited", false);
253         }
254
255         memlock = get_fdinfo(fd, "memlock");
256         if (memlock)
257                 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock));
258         free(memlock);
259
260         if (info->nr_map_ids)
261                 show_prog_maps(fd, info->nr_map_ids);
262
263         if (!hash_empty(prog_table.table)) {
264                 struct pinned_obj *obj;
265
266                 jsonw_name(json_wtr, "pinned");
267                 jsonw_start_array(json_wtr);
268                 hash_for_each_possible(prog_table.table, obj, hash, info->id) {
269                         if (obj->id == info->id)
270                                 jsonw_string(json_wtr, obj->path);
271                 }
272                 jsonw_end_array(json_wtr);
273         }
274
275         jsonw_end_object(json_wtr);
276 }
277
278 static void print_prog_plain(struct bpf_prog_info *info, int fd)
279 {
280         char *memlock;
281
282         printf("%u: ", info->id);
283         if (info->type < ARRAY_SIZE(prog_type_name))
284                 printf("%s  ", prog_type_name[info->type]);
285         else
286                 printf("type %u  ", info->type);
287
288         if (*info->name)
289                 printf("name %s  ", info->name);
290
291         printf("tag ");
292         fprint_hex(stdout, info->tag, BPF_TAG_SIZE, "");
293         print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
294         printf("\n");
295
296         if (info->load_time) {
297                 char buf[32];
298
299                 print_boot_time(info->load_time, buf, sizeof(buf));
300
301                 /* Piggy back on load_time, since 0 uid is a valid one */
302                 printf("\tloaded_at %s  uid %u\n", buf, info->created_by_uid);
303         }
304
305         printf("\txlated %uB", info->xlated_prog_len);
306
307         if (info->jited_prog_len)
308                 printf("  jited %uB", info->jited_prog_len);
309         else
310                 printf("  not jited");
311
312         memlock = get_fdinfo(fd, "memlock");
313         if (memlock)
314                 printf("  memlock %sB", memlock);
315         free(memlock);
316
317         if (info->nr_map_ids)
318                 show_prog_maps(fd, info->nr_map_ids);
319
320         if (!hash_empty(prog_table.table)) {
321                 struct pinned_obj *obj;
322
323                 printf("\n");
324                 hash_for_each_possible(prog_table.table, obj, hash, info->id) {
325                         if (obj->id == info->id)
326                                 printf("\tpinned %s\n", obj->path);
327                 }
328         }
329
330         printf("\n");
331 }
332
333 static int show_prog(int fd)
334 {
335         struct bpf_prog_info info = {};
336         __u32 len = sizeof(info);
337         int err;
338
339         err = bpf_obj_get_info_by_fd(fd, &info, &len);
340         if (err) {
341                 p_err("can't get prog info: %s", strerror(errno));
342                 return -1;
343         }
344
345         if (json_output)
346                 print_prog_json(&info, fd);
347         else
348                 print_prog_plain(&info, fd);
349
350         return 0;
351 }
352
353 static int do_show(int argc, char **argv)
354 {
355         __u32 id = 0;
356         int err;
357         int fd;
358
359         if (show_pinned)
360                 build_pinned_obj_table(&prog_table, BPF_OBJ_PROG);
361
362         if (argc == 2) {
363                 fd = prog_parse_fd(&argc, &argv);
364                 if (fd < 0)
365                         return -1;
366
367                 return show_prog(fd);
368         }
369
370         if (argc)
371                 return BAD_ARG();
372
373         if (json_output)
374                 jsonw_start_array(json_wtr);
375         while (true) {
376                 err = bpf_prog_get_next_id(id, &id);
377                 if (err) {
378                         if (errno == ENOENT) {
379                                 err = 0;
380                                 break;
381                         }
382                         p_err("can't get next program: %s%s", strerror(errno),
383                               errno == EINVAL ? " -- kernel too old?" : "");
384                         err = -1;
385                         break;
386                 }
387
388                 fd = bpf_prog_get_fd_by_id(id);
389                 if (fd < 0) {
390                         if (errno == ENOENT)
391                                 continue;
392                         p_err("can't get prog by id (%u): %s",
393                               id, strerror(errno));
394                         err = -1;
395                         break;
396                 }
397
398                 err = show_prog(fd);
399                 close(fd);
400                 if (err)
401                         break;
402         }
403
404         if (json_output)
405                 jsonw_end_array(json_wtr);
406
407         return err;
408 }
409
410 #define SYM_MAX_NAME    256
411
412 struct kernel_sym {
413         unsigned long address;
414         char name[SYM_MAX_NAME];
415 };
416
417 struct dump_data {
418         unsigned long address_call_base;
419         struct kernel_sym *sym_mapping;
420         __u32 sym_count;
421         char scratch_buff[SYM_MAX_NAME];
422 };
423
424 static int kernel_syms_cmp(const void *sym_a, const void *sym_b)
425 {
426         return ((struct kernel_sym *)sym_a)->address -
427                ((struct kernel_sym *)sym_b)->address;
428 }
429
430 static void kernel_syms_load(struct dump_data *dd)
431 {
432         struct kernel_sym *sym;
433         char buff[256];
434         void *tmp, *address;
435         FILE *fp;
436
437         fp = fopen("/proc/kallsyms", "r");
438         if (!fp)
439                 return;
440
441         while (!feof(fp)) {
442                 if (!fgets(buff, sizeof(buff), fp))
443                         break;
444                 tmp = realloc(dd->sym_mapping,
445                               (dd->sym_count + 1) *
446                               sizeof(*dd->sym_mapping));
447                 if (!tmp) {
448 out:
449                         free(dd->sym_mapping);
450                         dd->sym_mapping = NULL;
451                         fclose(fp);
452                         return;
453                 }
454                 dd->sym_mapping = tmp;
455                 sym = &dd->sym_mapping[dd->sym_count];
456                 if (sscanf(buff, "%p %*c %s", &address, sym->name) != 2)
457                         continue;
458                 sym->address = (unsigned long)address;
459                 if (!strcmp(sym->name, "__bpf_call_base")) {
460                         dd->address_call_base = sym->address;
461                         /* sysctl kernel.kptr_restrict was set */
462                         if (!sym->address)
463                                 goto out;
464                 }
465                 if (sym->address)
466                         dd->sym_count++;
467         }
468
469         fclose(fp);
470
471         qsort(dd->sym_mapping, dd->sym_count,
472               sizeof(*dd->sym_mapping), kernel_syms_cmp);
473 }
474
475 static void kernel_syms_destroy(struct dump_data *dd)
476 {
477         free(dd->sym_mapping);
478 }
479
480 static struct kernel_sym *kernel_syms_search(struct dump_data *dd,
481                                              unsigned long key)
482 {
483         struct kernel_sym sym = {
484                 .address = key,
485         };
486
487         return dd->sym_mapping ?
488                bsearch(&sym, dd->sym_mapping, dd->sym_count,
489                        sizeof(*dd->sym_mapping), kernel_syms_cmp) : NULL;
490 }
491
492 static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...)
493 {
494         va_list args;
495
496         va_start(args, fmt);
497         vprintf(fmt, args);
498         va_end(args);
499 }
500
501 static const char *print_call_pcrel(struct dump_data *dd,
502                                     struct kernel_sym *sym,
503                                     unsigned long address,
504                                     const struct bpf_insn *insn)
505 {
506         if (sym)
507                 snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
508                          "%+d#%s", insn->off, sym->name);
509         else
510                 snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
511                          "%+d#0x%lx", insn->off, address);
512         return dd->scratch_buff;
513 }
514
515 static const char *print_call_helper(struct dump_data *dd,
516                                      struct kernel_sym *sym,
517                                      unsigned long address)
518 {
519         if (sym)
520                 snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
521                          "%s", sym->name);
522         else
523                 snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
524                          "0x%lx", address);
525         return dd->scratch_buff;
526 }
527
528 static const char *print_call(void *private_data,
529                               const struct bpf_insn *insn)
530 {
531         struct dump_data *dd = private_data;
532         unsigned long address = dd->address_call_base + insn->imm;
533         struct kernel_sym *sym;
534
535         sym = kernel_syms_search(dd, address);
536         if (insn->src_reg == BPF_PSEUDO_CALL)
537                 return print_call_pcrel(dd, sym, address, insn);
538         else
539                 return print_call_helper(dd, sym, address);
540 }
541
542 static const char *print_imm(void *private_data,
543                              const struct bpf_insn *insn,
544                              __u64 full_imm)
545 {
546         struct dump_data *dd = private_data;
547
548         if (insn->src_reg == BPF_PSEUDO_MAP_FD)
549                 snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
550                          "map[id:%u]", insn->imm);
551         else
552                 snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
553                          "0x%llx", (unsigned long long)full_imm);
554         return dd->scratch_buff;
555 }
556
557 static void dump_xlated_plain(struct dump_data *dd, void *buf,
558                               unsigned int len, bool opcodes)
559 {
560         const struct bpf_insn_cbs cbs = {
561                 .cb_print       = print_insn,
562                 .cb_call        = print_call,
563                 .cb_imm         = print_imm,
564                 .private_data   = dd,
565         };
566         struct bpf_insn *insn = buf;
567         bool double_insn = false;
568         unsigned int i;
569
570         for (i = 0; i < len / sizeof(*insn); i++) {
571                 if (double_insn) {
572                         double_insn = false;
573                         continue;
574                 }
575
576                 double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW);
577
578                 printf("% 4d: ", i);
579                 print_bpf_insn(&cbs, NULL, insn + i, true);
580
581                 if (opcodes) {
582                         printf("       ");
583                         fprint_hex(stdout, insn + i, 8, " ");
584                         if (double_insn && i < len - 1) {
585                                 printf(" ");
586                                 fprint_hex(stdout, insn + i + 1, 8, " ");
587                         }
588                         printf("\n");
589                 }
590         }
591 }
592
593 static void print_insn_json(struct bpf_verifier_env *env, const char *fmt, ...)
594 {
595         unsigned int l = strlen(fmt);
596         char chomped_fmt[l];
597         va_list args;
598
599         va_start(args, fmt);
600         if (l > 0) {
601                 strncpy(chomped_fmt, fmt, l - 1);
602                 chomped_fmt[l - 1] = '\0';
603         }
604         jsonw_vprintf_enquote(json_wtr, chomped_fmt, args);
605         va_end(args);
606 }
607
608 static void dump_xlated_json(struct dump_data *dd, void *buf,
609                              unsigned int len, bool opcodes)
610 {
611         const struct bpf_insn_cbs cbs = {
612                 .cb_print       = print_insn_json,
613                 .cb_call        = print_call,
614                 .cb_imm         = print_imm,
615                 .private_data   = dd,
616         };
617         struct bpf_insn *insn = buf;
618         bool double_insn = false;
619         unsigned int i;
620
621         jsonw_start_array(json_wtr);
622         for (i = 0; i < len / sizeof(*insn); i++) {
623                 if (double_insn) {
624                         double_insn = false;
625                         continue;
626                 }
627                 double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW);
628
629                 jsonw_start_object(json_wtr);
630                 jsonw_name(json_wtr, "disasm");
631                 print_bpf_insn(&cbs, NULL, insn + i, true);
632
633                 if (opcodes) {
634                         jsonw_name(json_wtr, "opcodes");
635                         jsonw_start_object(json_wtr);
636
637                         jsonw_name(json_wtr, "code");
638                         jsonw_printf(json_wtr, "\"0x%02hhx\"", insn[i].code);
639
640                         jsonw_name(json_wtr, "src_reg");
641                         jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].src_reg);
642
643                         jsonw_name(json_wtr, "dst_reg");
644                         jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].dst_reg);
645
646                         jsonw_name(json_wtr, "off");
647                         print_hex_data_json((uint8_t *)(&insn[i].off), 2);
648
649                         jsonw_name(json_wtr, "imm");
650                         if (double_insn && i < len - 1)
651                                 print_hex_data_json((uint8_t *)(&insn[i].imm),
652                                                     12);
653                         else
654                                 print_hex_data_json((uint8_t *)(&insn[i].imm),
655                                                     4);
656                         jsonw_end_object(json_wtr);
657                 }
658                 jsonw_end_object(json_wtr);
659         }
660         jsonw_end_array(json_wtr);
661 }
662
663 static int do_dump(int argc, char **argv)
664 {
665         struct bpf_prog_info info = {};
666         struct dump_data dd = {};
667         __u32 len = sizeof(info);
668         unsigned int buf_size;
669         char *filepath = NULL;
670         bool opcodes = false;
671         unsigned char *buf;
672         __u32 *member_len;
673         __u64 *member_ptr;
674         ssize_t n;
675         int err;
676         int fd;
677
678         if (is_prefix(*argv, "jited")) {
679                 member_len = &info.jited_prog_len;
680                 member_ptr = &info.jited_prog_insns;
681         } else if (is_prefix(*argv, "xlated")) {
682                 member_len = &info.xlated_prog_len;
683                 member_ptr = &info.xlated_prog_insns;
684         } else {
685                 p_err("expected 'xlated' or 'jited', got: %s", *argv);
686                 return -1;
687         }
688         NEXT_ARG();
689
690         if (argc < 2)
691                 usage();
692
693         fd = prog_parse_fd(&argc, &argv);
694         if (fd < 0)
695                 return -1;
696
697         if (is_prefix(*argv, "file")) {
698                 NEXT_ARG();
699                 if (!argc) {
700                         p_err("expected file path");
701                         return -1;
702                 }
703
704                 filepath = *argv;
705                 NEXT_ARG();
706         } else if (is_prefix(*argv, "opcodes")) {
707                 opcodes = true;
708                 NEXT_ARG();
709         }
710
711         if (argc) {
712                 usage();
713                 return -1;
714         }
715
716         err = bpf_obj_get_info_by_fd(fd, &info, &len);
717         if (err) {
718                 p_err("can't get prog info: %s", strerror(errno));
719                 return -1;
720         }
721
722         if (!*member_len) {
723                 p_info("no instructions returned");
724                 close(fd);
725                 return 0;
726         }
727
728         buf_size = *member_len;
729
730         buf = malloc(buf_size);
731         if (!buf) {
732                 p_err("mem alloc failed");
733                 close(fd);
734                 return -1;
735         }
736
737         memset(&info, 0, sizeof(info));
738
739         *member_ptr = ptr_to_u64(buf);
740         *member_len = buf_size;
741
742         err = bpf_obj_get_info_by_fd(fd, &info, &len);
743         close(fd);
744         if (err) {
745                 p_err("can't get prog info: %s", strerror(errno));
746                 goto err_free;
747         }
748
749         if (*member_len > buf_size) {
750                 p_err("too many instructions returned");
751                 goto err_free;
752         }
753
754         if ((member_len == &info.jited_prog_len &&
755              info.jited_prog_insns == 0) ||
756             (member_len == &info.xlated_prog_len &&
757              info.xlated_prog_insns == 0)) {
758                 p_err("error retrieving insn dump: kernel.kptr_restrict set?");
759                 goto err_free;
760         }
761
762         if (filepath) {
763                 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
764                 if (fd < 0) {
765                         p_err("can't open file %s: %s", filepath,
766                               strerror(errno));
767                         goto err_free;
768                 }
769
770                 n = write(fd, buf, *member_len);
771                 close(fd);
772                 if (n != *member_len) {
773                         p_err("error writing output file: %s",
774                               n < 0 ? strerror(errno) : "short write");
775                         goto err_free;
776                 }
777
778                 if (json_output)
779                         jsonw_null(json_wtr);
780         } else {
781                 if (member_len == &info.jited_prog_len) {
782                         const char *name = NULL;
783
784                         if (info.ifindex) {
785                                 name = ifindex_to_bfd_name_ns(info.ifindex,
786                                                               info.netns_dev,
787                                                               info.netns_ino);
788                                 if (!name)
789                                         goto err_free;
790                         }
791
792                         disasm_print_insn(buf, *member_len, opcodes, name);
793                 } else {
794                         kernel_syms_load(&dd);
795                         if (json_output)
796                                 dump_xlated_json(&dd, buf, *member_len, opcodes);
797                         else
798                                 dump_xlated_plain(&dd, buf, *member_len, opcodes);
799                         kernel_syms_destroy(&dd);
800                 }
801         }
802
803         free(buf);
804         return 0;
805
806 err_free:
807         free(buf);
808         return -1;
809 }
810
811 static int do_pin(int argc, char **argv)
812 {
813         int err;
814
815         err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id);
816         if (!err && json_output)
817                 jsonw_null(json_wtr);
818         return err;
819 }
820
821 static int do_load(int argc, char **argv)
822 {
823         struct bpf_object *obj;
824         int prog_fd;
825
826         if (argc != 2)
827                 usage();
828
829         if (bpf_prog_load(argv[0], BPF_PROG_TYPE_UNSPEC, &obj, &prog_fd)) {
830                 p_err("failed to load program");
831                 return -1;
832         }
833
834         if (do_pin_fd(prog_fd, argv[1])) {
835                 p_err("failed to pin program");
836                 return -1;
837         }
838
839         if (json_output)
840                 jsonw_null(json_wtr);
841
842         return 0;
843 }
844
845 static int do_help(int argc, char **argv)
846 {
847         if (json_output) {
848                 jsonw_null(json_wtr);
849                 return 0;
850         }
851
852         fprintf(stderr,
853                 "Usage: %s %s { show | list } [PROG]\n"
854                 "       %s %s dump xlated PROG [{ file FILE | opcodes }]\n"
855                 "       %s %s dump jited  PROG [{ file FILE | opcodes }]\n"
856                 "       %s %s pin   PROG FILE\n"
857                 "       %s %s load  OBJ  FILE\n"
858                 "       %s %s help\n"
859                 "\n"
860                 "       " HELP_SPEC_PROGRAM "\n"
861                 "       " HELP_SPEC_OPTIONS "\n"
862                 "",
863                 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
864                 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]);
865
866         return 0;
867 }
868
869 static const struct cmd cmds[] = {
870         { "show",       do_show },
871         { "list",       do_show },
872         { "help",       do_help },
873         { "dump",       do_dump },
874         { "pin",        do_pin },
875         { "load",       do_load },
876         { 0 }
877 };
878
879 int do_prog(int argc, char **argv)
880 {
881         return cmd_select(cmds, argc, argv, do_help);
882 }