171bb428fSJakub Kicinski /* 271bb428fSJakub Kicinski * Copyright (C) 2017 Netronome Systems, Inc. 371bb428fSJakub Kicinski * 471bb428fSJakub Kicinski * This software is dual licensed under the GNU General License Version 2, 571bb428fSJakub Kicinski * June 1991 as shown in the file COPYING in the top-level directory of this 671bb428fSJakub Kicinski * source tree or the BSD 2-Clause License provided below. You have the 771bb428fSJakub Kicinski * option to license this software under the complete terms of either license. 871bb428fSJakub Kicinski * 971bb428fSJakub Kicinski * The BSD 2-Clause License: 1071bb428fSJakub Kicinski * 1171bb428fSJakub Kicinski * Redistribution and use in source and binary forms, with or 1271bb428fSJakub Kicinski * without modification, are permitted provided that the following 1371bb428fSJakub Kicinski * conditions are met: 1471bb428fSJakub Kicinski * 1571bb428fSJakub Kicinski * 1. Redistributions of source code must retain the above 1671bb428fSJakub Kicinski * copyright notice, this list of conditions and the following 1771bb428fSJakub Kicinski * disclaimer. 1871bb428fSJakub Kicinski * 1971bb428fSJakub Kicinski * 2. Redistributions in binary form must reproduce the above 2071bb428fSJakub Kicinski * copyright notice, this list of conditions and the following 2171bb428fSJakub Kicinski * disclaimer in the documentation and/or other materials 2271bb428fSJakub Kicinski * provided with the distribution. 2371bb428fSJakub Kicinski * 2471bb428fSJakub Kicinski * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2571bb428fSJakub Kicinski * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2671bb428fSJakub Kicinski * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2771bb428fSJakub Kicinski * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2871bb428fSJakub Kicinski * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2971bb428fSJakub Kicinski * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3071bb428fSJakub Kicinski * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3171bb428fSJakub Kicinski * SOFTWARE. 3271bb428fSJakub Kicinski */ 3371bb428fSJakub Kicinski 3471bb428fSJakub Kicinski /* Author: Jakub Kicinski <kubakici@wp.pl> */ 3571bb428fSJakub Kicinski 3671bb428fSJakub Kicinski #include <errno.h> 3771bb428fSJakub Kicinski #include <fcntl.h> 38c9c35995SJakub Kicinski #include <stdarg.h> 3971bb428fSJakub Kicinski #include <stdio.h> 4071bb428fSJakub Kicinski #include <stdlib.h> 4171bb428fSJakub Kicinski #include <string.h> 4271bb428fSJakub Kicinski #include <time.h> 4371bb428fSJakub Kicinski #include <unistd.h> 4471bb428fSJakub Kicinski #include <sys/types.h> 4571bb428fSJakub Kicinski #include <sys/stat.h> 4671bb428fSJakub Kicinski 4771bb428fSJakub Kicinski #include <bpf.h> 4871bb428fSJakub Kicinski 4971bb428fSJakub Kicinski #include "main.h" 50c9c35995SJakub Kicinski #include "disasm.h" 5171bb428fSJakub Kicinski 5271bb428fSJakub Kicinski static const char * const prog_type_name[] = { 5371bb428fSJakub Kicinski [BPF_PROG_TYPE_UNSPEC] = "unspec", 5471bb428fSJakub Kicinski [BPF_PROG_TYPE_SOCKET_FILTER] = "socket_filter", 5571bb428fSJakub Kicinski [BPF_PROG_TYPE_KPROBE] = "kprobe", 5671bb428fSJakub Kicinski [BPF_PROG_TYPE_SCHED_CLS] = "sched_cls", 5771bb428fSJakub Kicinski [BPF_PROG_TYPE_SCHED_ACT] = "sched_act", 5871bb428fSJakub Kicinski [BPF_PROG_TYPE_TRACEPOINT] = "tracepoint", 5971bb428fSJakub Kicinski [BPF_PROG_TYPE_XDP] = "xdp", 6071bb428fSJakub Kicinski [BPF_PROG_TYPE_PERF_EVENT] = "perf_event", 6171bb428fSJakub Kicinski [BPF_PROG_TYPE_CGROUP_SKB] = "cgroup_skb", 6271bb428fSJakub Kicinski [BPF_PROG_TYPE_CGROUP_SOCK] = "cgroup_sock", 6371bb428fSJakub Kicinski [BPF_PROG_TYPE_LWT_IN] = "lwt_in", 6471bb428fSJakub Kicinski [BPF_PROG_TYPE_LWT_OUT] = "lwt_out", 6571bb428fSJakub Kicinski [BPF_PROG_TYPE_LWT_XMIT] = "lwt_xmit", 6671bb428fSJakub Kicinski [BPF_PROG_TYPE_SOCK_OPS] = "sock_ops", 6771bb428fSJakub Kicinski [BPF_PROG_TYPE_SK_SKB] = "sk_skb", 6871bb428fSJakub Kicinski }; 6971bb428fSJakub Kicinski 7071bb428fSJakub Kicinski static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 7171bb428fSJakub Kicinski { 7271bb428fSJakub Kicinski struct timespec real_time_ts, boot_time_ts; 7371bb428fSJakub Kicinski time_t wallclock_secs; 7471bb428fSJakub Kicinski struct tm load_tm; 7571bb428fSJakub Kicinski 7671bb428fSJakub Kicinski buf[--size] = '\0'; 7771bb428fSJakub Kicinski 7871bb428fSJakub Kicinski if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 7971bb428fSJakub Kicinski clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 8071bb428fSJakub Kicinski perror("Can't read clocks"); 8171bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 8271bb428fSJakub Kicinski return; 8371bb428fSJakub Kicinski } 8471bb428fSJakub Kicinski 8571bb428fSJakub Kicinski wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 8671bb428fSJakub Kicinski nsecs / 1000000000; 8771bb428fSJakub Kicinski 8871bb428fSJakub Kicinski if (!localtime_r(&wallclock_secs, &load_tm)) { 8971bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 9071bb428fSJakub Kicinski return; 9171bb428fSJakub Kicinski } 9271bb428fSJakub Kicinski 9371bb428fSJakub Kicinski strftime(buf, size, "%b %d/%H:%M", &load_tm); 9471bb428fSJakub Kicinski } 9571bb428fSJakub Kicinski 9671bb428fSJakub Kicinski static int prog_fd_by_tag(unsigned char *tag) 9771bb428fSJakub Kicinski { 9871bb428fSJakub Kicinski struct bpf_prog_info info = {}; 9971bb428fSJakub Kicinski __u32 len = sizeof(info); 10071bb428fSJakub Kicinski unsigned int id = 0; 10171bb428fSJakub Kicinski int err; 10271bb428fSJakub Kicinski int fd; 10371bb428fSJakub Kicinski 10471bb428fSJakub Kicinski while (true) { 10571bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 10671bb428fSJakub Kicinski if (err) { 10771bb428fSJakub Kicinski err("%s\n", strerror(errno)); 10871bb428fSJakub Kicinski return -1; 10971bb428fSJakub Kicinski } 11071bb428fSJakub Kicinski 11171bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 11271bb428fSJakub Kicinski if (fd < 0) { 11371bb428fSJakub Kicinski err("can't get prog by id (%u): %s\n", 11471bb428fSJakub Kicinski id, strerror(errno)); 11571bb428fSJakub Kicinski return -1; 11671bb428fSJakub Kicinski } 11771bb428fSJakub Kicinski 11871bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 11971bb428fSJakub Kicinski if (err) { 12071bb428fSJakub Kicinski err("can't get prog info (%u): %s\n", 12171bb428fSJakub Kicinski id, strerror(errno)); 12271bb428fSJakub Kicinski close(fd); 12371bb428fSJakub Kicinski return -1; 12471bb428fSJakub Kicinski } 12571bb428fSJakub Kicinski 12671bb428fSJakub Kicinski if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) 12771bb428fSJakub Kicinski return fd; 12871bb428fSJakub Kicinski 12971bb428fSJakub Kicinski close(fd); 13071bb428fSJakub Kicinski } 13171bb428fSJakub Kicinski } 13271bb428fSJakub Kicinski 13371bb428fSJakub Kicinski int prog_parse_fd(int *argc, char ***argv) 13471bb428fSJakub Kicinski { 13571bb428fSJakub Kicinski int fd; 13671bb428fSJakub Kicinski 13771bb428fSJakub Kicinski if (is_prefix(**argv, "id")) { 13871bb428fSJakub Kicinski unsigned int id; 13971bb428fSJakub Kicinski char *endptr; 14071bb428fSJakub Kicinski 14171bb428fSJakub Kicinski NEXT_ARGP(); 14271bb428fSJakub Kicinski 14371bb428fSJakub Kicinski id = strtoul(**argv, &endptr, 0); 14471bb428fSJakub Kicinski if (*endptr) { 14571bb428fSJakub Kicinski err("can't parse %s as ID\n", **argv); 14671bb428fSJakub Kicinski return -1; 14771bb428fSJakub Kicinski } 14871bb428fSJakub Kicinski NEXT_ARGP(); 14971bb428fSJakub Kicinski 15071bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 15171bb428fSJakub Kicinski if (fd < 0) 15271bb428fSJakub Kicinski err("get by id (%u): %s\n", id, strerror(errno)); 15371bb428fSJakub Kicinski return fd; 15471bb428fSJakub Kicinski } else if (is_prefix(**argv, "tag")) { 15571bb428fSJakub Kicinski unsigned char tag[BPF_TAG_SIZE]; 15671bb428fSJakub Kicinski 15771bb428fSJakub Kicinski NEXT_ARGP(); 15871bb428fSJakub Kicinski 15971bb428fSJakub Kicinski if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 16071bb428fSJakub Kicinski tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 16171bb428fSJakub Kicinski != BPF_TAG_SIZE) { 16271bb428fSJakub Kicinski err("can't parse tag\n"); 16371bb428fSJakub Kicinski return -1; 16471bb428fSJakub Kicinski } 16571bb428fSJakub Kicinski NEXT_ARGP(); 16671bb428fSJakub Kicinski 16771bb428fSJakub Kicinski return prog_fd_by_tag(tag); 16871bb428fSJakub Kicinski } else if (is_prefix(**argv, "pinned")) { 16971bb428fSJakub Kicinski char *path; 17071bb428fSJakub Kicinski 17171bb428fSJakub Kicinski NEXT_ARGP(); 17271bb428fSJakub Kicinski 17371bb428fSJakub Kicinski path = **argv; 17471bb428fSJakub Kicinski NEXT_ARGP(); 17571bb428fSJakub Kicinski 17671bb428fSJakub Kicinski return open_obj_pinned_any(path, BPF_OBJ_PROG); 17771bb428fSJakub Kicinski } 17871bb428fSJakub Kicinski 17971bb428fSJakub Kicinski err("expected 'id', 'tag' or 'pinned', got: '%s'?\n", **argv); 18071bb428fSJakub Kicinski return -1; 18171bb428fSJakub Kicinski } 18271bb428fSJakub Kicinski 18371bb428fSJakub Kicinski static void show_prog_maps(int fd, u32 num_maps) 18471bb428fSJakub Kicinski { 18571bb428fSJakub Kicinski struct bpf_prog_info info = {}; 18671bb428fSJakub Kicinski __u32 len = sizeof(info); 18771bb428fSJakub Kicinski __u32 map_ids[num_maps]; 18871bb428fSJakub Kicinski unsigned int i; 18971bb428fSJakub Kicinski int err; 19071bb428fSJakub Kicinski 19171bb428fSJakub Kicinski info.nr_map_ids = num_maps; 19271bb428fSJakub Kicinski info.map_ids = ptr_to_u64(map_ids); 19371bb428fSJakub Kicinski 19471bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 19571bb428fSJakub Kicinski if (err || !info.nr_map_ids) 19671bb428fSJakub Kicinski return; 19771bb428fSJakub Kicinski 19871bb428fSJakub Kicinski printf(" map_ids "); 19971bb428fSJakub Kicinski for (i = 0; i < info.nr_map_ids; i++) 20071bb428fSJakub Kicinski printf("%u%s", map_ids[i], 20171bb428fSJakub Kicinski i == info.nr_map_ids - 1 ? "" : ","); 20271bb428fSJakub Kicinski } 20371bb428fSJakub Kicinski 20471bb428fSJakub Kicinski static int show_prog(int fd) 20571bb428fSJakub Kicinski { 20671bb428fSJakub Kicinski struct bpf_prog_info info = {}; 20771bb428fSJakub Kicinski __u32 len = sizeof(info); 20871bb428fSJakub Kicinski char *memlock; 20971bb428fSJakub Kicinski int err; 21071bb428fSJakub Kicinski 21171bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 21271bb428fSJakub Kicinski if (err) { 21371bb428fSJakub Kicinski err("can't get prog info: %s\n", strerror(errno)); 21471bb428fSJakub Kicinski return -1; 21571bb428fSJakub Kicinski } 21671bb428fSJakub Kicinski 21771bb428fSJakub Kicinski printf("%u: ", info.id); 21871bb428fSJakub Kicinski if (info.type < ARRAY_SIZE(prog_type_name)) 21971bb428fSJakub Kicinski printf("%s ", prog_type_name[info.type]); 22071bb428fSJakub Kicinski else 22171bb428fSJakub Kicinski printf("type %u ", info.type); 22271bb428fSJakub Kicinski 22371bb428fSJakub Kicinski if (*info.name) 22471bb428fSJakub Kicinski printf("name %s ", info.name); 22571bb428fSJakub Kicinski 22671bb428fSJakub Kicinski printf("tag "); 227*9cbe1f58SQuentin Monnet fprint_hex(stdout, info.tag, BPF_TAG_SIZE, ""); 22871bb428fSJakub Kicinski printf("\n"); 22971bb428fSJakub Kicinski 23071bb428fSJakub Kicinski if (info.load_time) { 23171bb428fSJakub Kicinski char buf[32]; 23271bb428fSJakub Kicinski 23371bb428fSJakub Kicinski print_boot_time(info.load_time, buf, sizeof(buf)); 23471bb428fSJakub Kicinski 23571bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 23671bb428fSJakub Kicinski printf("\tloaded_at %s uid %u\n", buf, info.created_by_uid); 23771bb428fSJakub Kicinski } 23871bb428fSJakub Kicinski 23971bb428fSJakub Kicinski printf("\txlated %uB", info.xlated_prog_len); 24071bb428fSJakub Kicinski 24171bb428fSJakub Kicinski if (info.jited_prog_len) 24271bb428fSJakub Kicinski printf(" jited %uB", info.jited_prog_len); 24371bb428fSJakub Kicinski else 24471bb428fSJakub Kicinski printf(" not jited"); 24571bb428fSJakub Kicinski 24671bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 24771bb428fSJakub Kicinski if (memlock) 24871bb428fSJakub Kicinski printf(" memlock %sB", memlock); 24971bb428fSJakub Kicinski free(memlock); 25071bb428fSJakub Kicinski 25171bb428fSJakub Kicinski if (info.nr_map_ids) 25271bb428fSJakub Kicinski show_prog_maps(fd, info.nr_map_ids); 25371bb428fSJakub Kicinski 25471bb428fSJakub Kicinski printf("\n"); 25571bb428fSJakub Kicinski 25671bb428fSJakub Kicinski return 0; 25771bb428fSJakub Kicinski } 25871bb428fSJakub Kicinski 25971bb428fSJakub Kicinski static int do_show(int argc, char **argv) 26071bb428fSJakub Kicinski { __u32 id = 0; 26171bb428fSJakub Kicinski int err; 26271bb428fSJakub Kicinski int fd; 26371bb428fSJakub Kicinski 26471bb428fSJakub Kicinski if (argc == 2) { 26571bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 26671bb428fSJakub Kicinski if (fd < 0) 26771bb428fSJakub Kicinski return -1; 26871bb428fSJakub Kicinski 26971bb428fSJakub Kicinski return show_prog(fd); 27071bb428fSJakub Kicinski } 27171bb428fSJakub Kicinski 27271bb428fSJakub Kicinski if (argc) 27371bb428fSJakub Kicinski return BAD_ARG(); 27471bb428fSJakub Kicinski 27571bb428fSJakub Kicinski while (true) { 27671bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 27771bb428fSJakub Kicinski if (err) { 27871bb428fSJakub Kicinski if (errno == ENOENT) 27971bb428fSJakub Kicinski break; 28071bb428fSJakub Kicinski err("can't get next program: %s\n", strerror(errno)); 28171bb428fSJakub Kicinski if (errno == EINVAL) 28271bb428fSJakub Kicinski err("kernel too old?\n"); 28371bb428fSJakub Kicinski return -1; 28471bb428fSJakub Kicinski } 28571bb428fSJakub Kicinski 28671bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 28771bb428fSJakub Kicinski if (fd < 0) { 28871bb428fSJakub Kicinski err("can't get prog by id (%u): %s\n", 28971bb428fSJakub Kicinski id, strerror(errno)); 29071bb428fSJakub Kicinski return -1; 29171bb428fSJakub Kicinski } 29271bb428fSJakub Kicinski 29371bb428fSJakub Kicinski err = show_prog(fd); 29471bb428fSJakub Kicinski close(fd); 29571bb428fSJakub Kicinski if (err) 29671bb428fSJakub Kicinski return err; 29771bb428fSJakub Kicinski } 29871bb428fSJakub Kicinski 29971bb428fSJakub Kicinski return 0; 30071bb428fSJakub Kicinski } 30171bb428fSJakub Kicinski 302c9c35995SJakub Kicinski static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...) 303c9c35995SJakub Kicinski { 304c9c35995SJakub Kicinski va_list args; 305c9c35995SJakub Kicinski 306c9c35995SJakub Kicinski va_start(args, fmt); 307c9c35995SJakub Kicinski vprintf(fmt, args); 308c9c35995SJakub Kicinski va_end(args); 309c9c35995SJakub Kicinski } 310c9c35995SJakub Kicinski 311c9c35995SJakub Kicinski static void dump_xlated(void *buf, unsigned int len, bool opcodes) 312c9c35995SJakub Kicinski { 313c9c35995SJakub Kicinski struct bpf_insn *insn = buf; 314c9c35995SJakub Kicinski unsigned int i; 315c9c35995SJakub Kicinski 316c9c35995SJakub Kicinski for (i = 0; i < len / sizeof(*insn); i++) { 317c9c35995SJakub Kicinski printf("% 4d: ", i); 318c9c35995SJakub Kicinski print_bpf_insn(print_insn, NULL, insn + i, true); 319c9c35995SJakub Kicinski 320c9c35995SJakub Kicinski if (opcodes) { 321c9c35995SJakub Kicinski printf(" "); 322*9cbe1f58SQuentin Monnet fprint_hex(stdout, insn + i, 8, " "); 323c9c35995SJakub Kicinski printf("\n"); 324c9c35995SJakub Kicinski } 325c9c35995SJakub Kicinski 326c9c35995SJakub Kicinski if (insn[i].code == (BPF_LD | BPF_IMM | BPF_DW)) 327c9c35995SJakub Kicinski i++; 328c9c35995SJakub Kicinski } 329c9c35995SJakub Kicinski } 330c9c35995SJakub Kicinski 33171bb428fSJakub Kicinski static int do_dump(int argc, char **argv) 33271bb428fSJakub Kicinski { 33371bb428fSJakub Kicinski struct bpf_prog_info info = {}; 33471bb428fSJakub Kicinski __u32 len = sizeof(info); 33571bb428fSJakub Kicinski unsigned int buf_size; 33671bb428fSJakub Kicinski char *filepath = NULL; 33771bb428fSJakub Kicinski bool opcodes = false; 33871bb428fSJakub Kicinski unsigned char *buf; 33971bb428fSJakub Kicinski __u32 *member_len; 34071bb428fSJakub Kicinski __u64 *member_ptr; 34171bb428fSJakub Kicinski ssize_t n; 34271bb428fSJakub Kicinski int err; 34371bb428fSJakub Kicinski int fd; 34471bb428fSJakub Kicinski 34571bb428fSJakub Kicinski if (is_prefix(*argv, "jited")) { 34671bb428fSJakub Kicinski member_len = &info.jited_prog_len; 34771bb428fSJakub Kicinski member_ptr = &info.jited_prog_insns; 34871bb428fSJakub Kicinski } else if (is_prefix(*argv, "xlated")) { 34971bb428fSJakub Kicinski member_len = &info.xlated_prog_len; 35071bb428fSJakub Kicinski member_ptr = &info.xlated_prog_insns; 35171bb428fSJakub Kicinski } else { 35271bb428fSJakub Kicinski err("expected 'xlated' or 'jited', got: %s\n", *argv); 35371bb428fSJakub Kicinski return -1; 35471bb428fSJakub Kicinski } 35571bb428fSJakub Kicinski NEXT_ARG(); 35671bb428fSJakub Kicinski 35771bb428fSJakub Kicinski if (argc < 2) 35871bb428fSJakub Kicinski usage(); 35971bb428fSJakub Kicinski 36071bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 36171bb428fSJakub Kicinski if (fd < 0) 36271bb428fSJakub Kicinski return -1; 36371bb428fSJakub Kicinski 36471bb428fSJakub Kicinski if (is_prefix(*argv, "file")) { 36571bb428fSJakub Kicinski NEXT_ARG(); 36671bb428fSJakub Kicinski if (!argc) { 36771bb428fSJakub Kicinski err("expected file path\n"); 36871bb428fSJakub Kicinski return -1; 36971bb428fSJakub Kicinski } 37071bb428fSJakub Kicinski 37171bb428fSJakub Kicinski filepath = *argv; 37271bb428fSJakub Kicinski NEXT_ARG(); 37371bb428fSJakub Kicinski } else if (is_prefix(*argv, "opcodes")) { 37471bb428fSJakub Kicinski opcodes = true; 37571bb428fSJakub Kicinski NEXT_ARG(); 37671bb428fSJakub Kicinski } 37771bb428fSJakub Kicinski 37871bb428fSJakub Kicinski if (argc) { 37971bb428fSJakub Kicinski usage(); 38071bb428fSJakub Kicinski return -1; 38171bb428fSJakub Kicinski } 38271bb428fSJakub Kicinski 38371bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 38471bb428fSJakub Kicinski if (err) { 38571bb428fSJakub Kicinski err("can't get prog info: %s\n", strerror(errno)); 38671bb428fSJakub Kicinski return -1; 38771bb428fSJakub Kicinski } 38871bb428fSJakub Kicinski 38971bb428fSJakub Kicinski if (!*member_len) { 39071bb428fSJakub Kicinski info("no instructions returned\n"); 39171bb428fSJakub Kicinski close(fd); 39271bb428fSJakub Kicinski return 0; 39371bb428fSJakub Kicinski } 39471bb428fSJakub Kicinski 39571bb428fSJakub Kicinski buf_size = *member_len; 39671bb428fSJakub Kicinski 39771bb428fSJakub Kicinski buf = malloc(buf_size); 39871bb428fSJakub Kicinski if (!buf) { 39971bb428fSJakub Kicinski err("mem alloc failed\n"); 40071bb428fSJakub Kicinski close(fd); 40171bb428fSJakub Kicinski return -1; 40271bb428fSJakub Kicinski } 40371bb428fSJakub Kicinski 40471bb428fSJakub Kicinski memset(&info, 0, sizeof(info)); 40571bb428fSJakub Kicinski 40671bb428fSJakub Kicinski *member_ptr = ptr_to_u64(buf); 40771bb428fSJakub Kicinski *member_len = buf_size; 40871bb428fSJakub Kicinski 40971bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 41071bb428fSJakub Kicinski close(fd); 41171bb428fSJakub Kicinski if (err) { 41271bb428fSJakub Kicinski err("can't get prog info: %s\n", strerror(errno)); 41371bb428fSJakub Kicinski goto err_free; 41471bb428fSJakub Kicinski } 41571bb428fSJakub Kicinski 41671bb428fSJakub Kicinski if (*member_len > buf_size) { 41771bb428fSJakub Kicinski info("too many instructions returned\n"); 41871bb428fSJakub Kicinski goto err_free; 41971bb428fSJakub Kicinski } 42071bb428fSJakub Kicinski 42171bb428fSJakub Kicinski if (filepath) { 42271bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 42371bb428fSJakub Kicinski if (fd < 0) { 42471bb428fSJakub Kicinski err("can't open file %s: %s\n", filepath, 42571bb428fSJakub Kicinski strerror(errno)); 42671bb428fSJakub Kicinski goto err_free; 42771bb428fSJakub Kicinski } 42871bb428fSJakub Kicinski 42971bb428fSJakub Kicinski n = write(fd, buf, *member_len); 43071bb428fSJakub Kicinski close(fd); 43171bb428fSJakub Kicinski if (n != *member_len) { 43271bb428fSJakub Kicinski err("error writing output file: %s\n", 43371bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 43471bb428fSJakub Kicinski goto err_free; 43571bb428fSJakub Kicinski } 43671bb428fSJakub Kicinski } else { 437c9c35995SJakub Kicinski if (member_len == &info.jited_prog_len) 43871bb428fSJakub Kicinski disasm_print_insn(buf, *member_len, opcodes); 439c9c35995SJakub Kicinski else 440c9c35995SJakub Kicinski dump_xlated(buf, *member_len, opcodes); 44171bb428fSJakub Kicinski } 44271bb428fSJakub Kicinski 44371bb428fSJakub Kicinski free(buf); 44471bb428fSJakub Kicinski 44571bb428fSJakub Kicinski return 0; 44671bb428fSJakub Kicinski 44771bb428fSJakub Kicinski err_free: 44871bb428fSJakub Kicinski free(buf); 44971bb428fSJakub Kicinski return -1; 45071bb428fSJakub Kicinski } 45171bb428fSJakub Kicinski 45271bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 45371bb428fSJakub Kicinski { 45471bb428fSJakub Kicinski return do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 45571bb428fSJakub Kicinski } 45671bb428fSJakub Kicinski 45771bb428fSJakub Kicinski static int do_help(int argc, char **argv) 45871bb428fSJakub Kicinski { 45971bb428fSJakub Kicinski fprintf(stderr, 46071bb428fSJakub Kicinski "Usage: %s %s show [PROG]\n" 461c9c35995SJakub Kicinski " %s %s dump xlated PROG [file FILE] [opcodes]\n" 46271bb428fSJakub Kicinski " %s %s dump jited PROG [file FILE] [opcodes]\n" 46371bb428fSJakub Kicinski " %s %s pin PROG FILE\n" 46471bb428fSJakub Kicinski " %s %s help\n" 46571bb428fSJakub Kicinski "\n" 46671bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 46771bb428fSJakub Kicinski "", 46871bb428fSJakub Kicinski bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 46971bb428fSJakub Kicinski bin_name, argv[-2], bin_name, argv[-2]); 47071bb428fSJakub Kicinski 47171bb428fSJakub Kicinski return 0; 47271bb428fSJakub Kicinski } 47371bb428fSJakub Kicinski 47471bb428fSJakub Kicinski static const struct cmd cmds[] = { 47571bb428fSJakub Kicinski { "show", do_show }, 47671bb428fSJakub Kicinski { "dump", do_dump }, 47771bb428fSJakub Kicinski { "pin", do_pin }, 47871bb428fSJakub Kicinski { 0 } 47971bb428fSJakub Kicinski }; 48071bb428fSJakub Kicinski 48171bb428fSJakub Kicinski int do_prog(int argc, char **argv) 48271bb428fSJakub Kicinski { 48371bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 48471bb428fSJakub Kicinski } 485