1*71bb428fSJakub Kicinski /* 2*71bb428fSJakub Kicinski * Copyright (C) 2017 Netronome Systems, Inc. 3*71bb428fSJakub Kicinski * 4*71bb428fSJakub Kicinski * This software is dual licensed under the GNU General License Version 2, 5*71bb428fSJakub Kicinski * June 1991 as shown in the file COPYING in the top-level directory of this 6*71bb428fSJakub Kicinski * source tree or the BSD 2-Clause License provided below. You have the 7*71bb428fSJakub Kicinski * option to license this software under the complete terms of either license. 8*71bb428fSJakub Kicinski * 9*71bb428fSJakub Kicinski * The BSD 2-Clause License: 10*71bb428fSJakub Kicinski * 11*71bb428fSJakub Kicinski * Redistribution and use in source and binary forms, with or 12*71bb428fSJakub Kicinski * without modification, are permitted provided that the following 13*71bb428fSJakub Kicinski * conditions are met: 14*71bb428fSJakub Kicinski * 15*71bb428fSJakub Kicinski * 1. Redistributions of source code must retain the above 16*71bb428fSJakub Kicinski * copyright notice, this list of conditions and the following 17*71bb428fSJakub Kicinski * disclaimer. 18*71bb428fSJakub Kicinski * 19*71bb428fSJakub Kicinski * 2. Redistributions in binary form must reproduce the above 20*71bb428fSJakub Kicinski * copyright notice, this list of conditions and the following 21*71bb428fSJakub Kicinski * disclaimer in the documentation and/or other materials 22*71bb428fSJakub Kicinski * provided with the distribution. 23*71bb428fSJakub Kicinski * 24*71bb428fSJakub Kicinski * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25*71bb428fSJakub Kicinski * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26*71bb428fSJakub Kicinski * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27*71bb428fSJakub Kicinski * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28*71bb428fSJakub Kicinski * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29*71bb428fSJakub Kicinski * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30*71bb428fSJakub Kicinski * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31*71bb428fSJakub Kicinski * SOFTWARE. 32*71bb428fSJakub Kicinski */ 33*71bb428fSJakub Kicinski 34*71bb428fSJakub Kicinski /* Author: Jakub Kicinski <kubakici@wp.pl> */ 35*71bb428fSJakub Kicinski 36*71bb428fSJakub Kicinski #include <errno.h> 37*71bb428fSJakub Kicinski #include <fcntl.h> 38*71bb428fSJakub Kicinski #include <stdio.h> 39*71bb428fSJakub Kicinski #include <stdlib.h> 40*71bb428fSJakub Kicinski #include <string.h> 41*71bb428fSJakub Kicinski #include <time.h> 42*71bb428fSJakub Kicinski #include <unistd.h> 43*71bb428fSJakub Kicinski #include <sys/types.h> 44*71bb428fSJakub Kicinski #include <sys/stat.h> 45*71bb428fSJakub Kicinski 46*71bb428fSJakub Kicinski #include <bpf.h> 47*71bb428fSJakub Kicinski 48*71bb428fSJakub Kicinski #include "main.h" 49*71bb428fSJakub Kicinski 50*71bb428fSJakub Kicinski static const char * const prog_type_name[] = { 51*71bb428fSJakub Kicinski [BPF_PROG_TYPE_UNSPEC] = "unspec", 52*71bb428fSJakub Kicinski [BPF_PROG_TYPE_SOCKET_FILTER] = "socket_filter", 53*71bb428fSJakub Kicinski [BPF_PROG_TYPE_KPROBE] = "kprobe", 54*71bb428fSJakub Kicinski [BPF_PROG_TYPE_SCHED_CLS] = "sched_cls", 55*71bb428fSJakub Kicinski [BPF_PROG_TYPE_SCHED_ACT] = "sched_act", 56*71bb428fSJakub Kicinski [BPF_PROG_TYPE_TRACEPOINT] = "tracepoint", 57*71bb428fSJakub Kicinski [BPF_PROG_TYPE_XDP] = "xdp", 58*71bb428fSJakub Kicinski [BPF_PROG_TYPE_PERF_EVENT] = "perf_event", 59*71bb428fSJakub Kicinski [BPF_PROG_TYPE_CGROUP_SKB] = "cgroup_skb", 60*71bb428fSJakub Kicinski [BPF_PROG_TYPE_CGROUP_SOCK] = "cgroup_sock", 61*71bb428fSJakub Kicinski [BPF_PROG_TYPE_LWT_IN] = "lwt_in", 62*71bb428fSJakub Kicinski [BPF_PROG_TYPE_LWT_OUT] = "lwt_out", 63*71bb428fSJakub Kicinski [BPF_PROG_TYPE_LWT_XMIT] = "lwt_xmit", 64*71bb428fSJakub Kicinski [BPF_PROG_TYPE_SOCK_OPS] = "sock_ops", 65*71bb428fSJakub Kicinski [BPF_PROG_TYPE_SK_SKB] = "sk_skb", 66*71bb428fSJakub Kicinski }; 67*71bb428fSJakub Kicinski 68*71bb428fSJakub Kicinski static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 69*71bb428fSJakub Kicinski { 70*71bb428fSJakub Kicinski struct timespec real_time_ts, boot_time_ts; 71*71bb428fSJakub Kicinski time_t wallclock_secs; 72*71bb428fSJakub Kicinski struct tm load_tm; 73*71bb428fSJakub Kicinski 74*71bb428fSJakub Kicinski buf[--size] = '\0'; 75*71bb428fSJakub Kicinski 76*71bb428fSJakub Kicinski if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 77*71bb428fSJakub Kicinski clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 78*71bb428fSJakub Kicinski perror("Can't read clocks"); 79*71bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 80*71bb428fSJakub Kicinski return; 81*71bb428fSJakub Kicinski } 82*71bb428fSJakub Kicinski 83*71bb428fSJakub Kicinski wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 84*71bb428fSJakub Kicinski nsecs / 1000000000; 85*71bb428fSJakub Kicinski 86*71bb428fSJakub Kicinski if (!localtime_r(&wallclock_secs, &load_tm)) { 87*71bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 88*71bb428fSJakub Kicinski return; 89*71bb428fSJakub Kicinski } 90*71bb428fSJakub Kicinski 91*71bb428fSJakub Kicinski strftime(buf, size, "%b %d/%H:%M", &load_tm); 92*71bb428fSJakub Kicinski } 93*71bb428fSJakub Kicinski 94*71bb428fSJakub Kicinski static int prog_fd_by_tag(unsigned char *tag) 95*71bb428fSJakub Kicinski { 96*71bb428fSJakub Kicinski struct bpf_prog_info info = {}; 97*71bb428fSJakub Kicinski __u32 len = sizeof(info); 98*71bb428fSJakub Kicinski unsigned int id = 0; 99*71bb428fSJakub Kicinski int err; 100*71bb428fSJakub Kicinski int fd; 101*71bb428fSJakub Kicinski 102*71bb428fSJakub Kicinski while (true) { 103*71bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 104*71bb428fSJakub Kicinski if (err) { 105*71bb428fSJakub Kicinski err("%s\n", strerror(errno)); 106*71bb428fSJakub Kicinski return -1; 107*71bb428fSJakub Kicinski } 108*71bb428fSJakub Kicinski 109*71bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 110*71bb428fSJakub Kicinski if (fd < 0) { 111*71bb428fSJakub Kicinski err("can't get prog by id (%u): %s\n", 112*71bb428fSJakub Kicinski id, strerror(errno)); 113*71bb428fSJakub Kicinski return -1; 114*71bb428fSJakub Kicinski } 115*71bb428fSJakub Kicinski 116*71bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 117*71bb428fSJakub Kicinski if (err) { 118*71bb428fSJakub Kicinski err("can't get prog info (%u): %s\n", 119*71bb428fSJakub Kicinski id, strerror(errno)); 120*71bb428fSJakub Kicinski close(fd); 121*71bb428fSJakub Kicinski return -1; 122*71bb428fSJakub Kicinski } 123*71bb428fSJakub Kicinski 124*71bb428fSJakub Kicinski if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) 125*71bb428fSJakub Kicinski return fd; 126*71bb428fSJakub Kicinski 127*71bb428fSJakub Kicinski close(fd); 128*71bb428fSJakub Kicinski } 129*71bb428fSJakub Kicinski } 130*71bb428fSJakub Kicinski 131*71bb428fSJakub Kicinski int prog_parse_fd(int *argc, char ***argv) 132*71bb428fSJakub Kicinski { 133*71bb428fSJakub Kicinski int fd; 134*71bb428fSJakub Kicinski 135*71bb428fSJakub Kicinski if (is_prefix(**argv, "id")) { 136*71bb428fSJakub Kicinski unsigned int id; 137*71bb428fSJakub Kicinski char *endptr; 138*71bb428fSJakub Kicinski 139*71bb428fSJakub Kicinski NEXT_ARGP(); 140*71bb428fSJakub Kicinski 141*71bb428fSJakub Kicinski id = strtoul(**argv, &endptr, 0); 142*71bb428fSJakub Kicinski if (*endptr) { 143*71bb428fSJakub Kicinski err("can't parse %s as ID\n", **argv); 144*71bb428fSJakub Kicinski return -1; 145*71bb428fSJakub Kicinski } 146*71bb428fSJakub Kicinski NEXT_ARGP(); 147*71bb428fSJakub Kicinski 148*71bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 149*71bb428fSJakub Kicinski if (fd < 0) 150*71bb428fSJakub Kicinski err("get by id (%u): %s\n", id, strerror(errno)); 151*71bb428fSJakub Kicinski return fd; 152*71bb428fSJakub Kicinski } else if (is_prefix(**argv, "tag")) { 153*71bb428fSJakub Kicinski unsigned char tag[BPF_TAG_SIZE]; 154*71bb428fSJakub Kicinski 155*71bb428fSJakub Kicinski NEXT_ARGP(); 156*71bb428fSJakub Kicinski 157*71bb428fSJakub Kicinski if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 158*71bb428fSJakub Kicinski tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 159*71bb428fSJakub Kicinski != BPF_TAG_SIZE) { 160*71bb428fSJakub Kicinski err("can't parse tag\n"); 161*71bb428fSJakub Kicinski return -1; 162*71bb428fSJakub Kicinski } 163*71bb428fSJakub Kicinski NEXT_ARGP(); 164*71bb428fSJakub Kicinski 165*71bb428fSJakub Kicinski return prog_fd_by_tag(tag); 166*71bb428fSJakub Kicinski } else if (is_prefix(**argv, "pinned")) { 167*71bb428fSJakub Kicinski char *path; 168*71bb428fSJakub Kicinski 169*71bb428fSJakub Kicinski NEXT_ARGP(); 170*71bb428fSJakub Kicinski 171*71bb428fSJakub Kicinski path = **argv; 172*71bb428fSJakub Kicinski NEXT_ARGP(); 173*71bb428fSJakub Kicinski 174*71bb428fSJakub Kicinski return open_obj_pinned_any(path, BPF_OBJ_PROG); 175*71bb428fSJakub Kicinski } 176*71bb428fSJakub Kicinski 177*71bb428fSJakub Kicinski err("expected 'id', 'tag' or 'pinned', got: '%s'?\n", **argv); 178*71bb428fSJakub Kicinski return -1; 179*71bb428fSJakub Kicinski } 180*71bb428fSJakub Kicinski 181*71bb428fSJakub Kicinski static void show_prog_maps(int fd, u32 num_maps) 182*71bb428fSJakub Kicinski { 183*71bb428fSJakub Kicinski struct bpf_prog_info info = {}; 184*71bb428fSJakub Kicinski __u32 len = sizeof(info); 185*71bb428fSJakub Kicinski __u32 map_ids[num_maps]; 186*71bb428fSJakub Kicinski unsigned int i; 187*71bb428fSJakub Kicinski int err; 188*71bb428fSJakub Kicinski 189*71bb428fSJakub Kicinski info.nr_map_ids = num_maps; 190*71bb428fSJakub Kicinski info.map_ids = ptr_to_u64(map_ids); 191*71bb428fSJakub Kicinski 192*71bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 193*71bb428fSJakub Kicinski if (err || !info.nr_map_ids) 194*71bb428fSJakub Kicinski return; 195*71bb428fSJakub Kicinski 196*71bb428fSJakub Kicinski printf(" map_ids "); 197*71bb428fSJakub Kicinski for (i = 0; i < info.nr_map_ids; i++) 198*71bb428fSJakub Kicinski printf("%u%s", map_ids[i], 199*71bb428fSJakub Kicinski i == info.nr_map_ids - 1 ? "" : ","); 200*71bb428fSJakub Kicinski } 201*71bb428fSJakub Kicinski 202*71bb428fSJakub Kicinski static int show_prog(int fd) 203*71bb428fSJakub Kicinski { 204*71bb428fSJakub Kicinski struct bpf_prog_info info = {}; 205*71bb428fSJakub Kicinski __u32 len = sizeof(info); 206*71bb428fSJakub Kicinski char *memlock; 207*71bb428fSJakub Kicinski int err; 208*71bb428fSJakub Kicinski 209*71bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 210*71bb428fSJakub Kicinski if (err) { 211*71bb428fSJakub Kicinski err("can't get prog info: %s\n", strerror(errno)); 212*71bb428fSJakub Kicinski return -1; 213*71bb428fSJakub Kicinski } 214*71bb428fSJakub Kicinski 215*71bb428fSJakub Kicinski printf("%u: ", info.id); 216*71bb428fSJakub Kicinski if (info.type < ARRAY_SIZE(prog_type_name)) 217*71bb428fSJakub Kicinski printf("%s ", prog_type_name[info.type]); 218*71bb428fSJakub Kicinski else 219*71bb428fSJakub Kicinski printf("type %u ", info.type); 220*71bb428fSJakub Kicinski 221*71bb428fSJakub Kicinski if (*info.name) 222*71bb428fSJakub Kicinski printf("name %s ", info.name); 223*71bb428fSJakub Kicinski 224*71bb428fSJakub Kicinski printf("tag "); 225*71bb428fSJakub Kicinski print_hex(info.tag, BPF_TAG_SIZE, ":"); 226*71bb428fSJakub Kicinski printf("\n"); 227*71bb428fSJakub Kicinski 228*71bb428fSJakub Kicinski if (info.load_time) { 229*71bb428fSJakub Kicinski char buf[32]; 230*71bb428fSJakub Kicinski 231*71bb428fSJakub Kicinski print_boot_time(info.load_time, buf, sizeof(buf)); 232*71bb428fSJakub Kicinski 233*71bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 234*71bb428fSJakub Kicinski printf("\tloaded_at %s uid %u\n", buf, info.created_by_uid); 235*71bb428fSJakub Kicinski } 236*71bb428fSJakub Kicinski 237*71bb428fSJakub Kicinski printf("\txlated %uB", info.xlated_prog_len); 238*71bb428fSJakub Kicinski 239*71bb428fSJakub Kicinski if (info.jited_prog_len) 240*71bb428fSJakub Kicinski printf(" jited %uB", info.jited_prog_len); 241*71bb428fSJakub Kicinski else 242*71bb428fSJakub Kicinski printf(" not jited"); 243*71bb428fSJakub Kicinski 244*71bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 245*71bb428fSJakub Kicinski if (memlock) 246*71bb428fSJakub Kicinski printf(" memlock %sB", memlock); 247*71bb428fSJakub Kicinski free(memlock); 248*71bb428fSJakub Kicinski 249*71bb428fSJakub Kicinski if (info.nr_map_ids) 250*71bb428fSJakub Kicinski show_prog_maps(fd, info.nr_map_ids); 251*71bb428fSJakub Kicinski 252*71bb428fSJakub Kicinski printf("\n"); 253*71bb428fSJakub Kicinski 254*71bb428fSJakub Kicinski return 0; 255*71bb428fSJakub Kicinski } 256*71bb428fSJakub Kicinski 257*71bb428fSJakub Kicinski static int do_show(int argc, char **argv) 258*71bb428fSJakub Kicinski { __u32 id = 0; 259*71bb428fSJakub Kicinski int err; 260*71bb428fSJakub Kicinski int fd; 261*71bb428fSJakub Kicinski 262*71bb428fSJakub Kicinski if (argc == 2) { 263*71bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 264*71bb428fSJakub Kicinski if (fd < 0) 265*71bb428fSJakub Kicinski return -1; 266*71bb428fSJakub Kicinski 267*71bb428fSJakub Kicinski return show_prog(fd); 268*71bb428fSJakub Kicinski } 269*71bb428fSJakub Kicinski 270*71bb428fSJakub Kicinski if (argc) 271*71bb428fSJakub Kicinski return BAD_ARG(); 272*71bb428fSJakub Kicinski 273*71bb428fSJakub Kicinski while (true) { 274*71bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 275*71bb428fSJakub Kicinski if (err) { 276*71bb428fSJakub Kicinski if (errno == ENOENT) 277*71bb428fSJakub Kicinski break; 278*71bb428fSJakub Kicinski err("can't get next program: %s\n", strerror(errno)); 279*71bb428fSJakub Kicinski if (errno == EINVAL) 280*71bb428fSJakub Kicinski err("kernel too old?\n"); 281*71bb428fSJakub Kicinski return -1; 282*71bb428fSJakub Kicinski } 283*71bb428fSJakub Kicinski 284*71bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 285*71bb428fSJakub Kicinski if (fd < 0) { 286*71bb428fSJakub Kicinski err("can't get prog by id (%u): %s\n", 287*71bb428fSJakub Kicinski id, strerror(errno)); 288*71bb428fSJakub Kicinski return -1; 289*71bb428fSJakub Kicinski } 290*71bb428fSJakub Kicinski 291*71bb428fSJakub Kicinski err = show_prog(fd); 292*71bb428fSJakub Kicinski close(fd); 293*71bb428fSJakub Kicinski if (err) 294*71bb428fSJakub Kicinski return err; 295*71bb428fSJakub Kicinski } 296*71bb428fSJakub Kicinski 297*71bb428fSJakub Kicinski return 0; 298*71bb428fSJakub Kicinski } 299*71bb428fSJakub Kicinski 300*71bb428fSJakub Kicinski static int do_dump(int argc, char **argv) 301*71bb428fSJakub Kicinski { 302*71bb428fSJakub Kicinski struct bpf_prog_info info = {}; 303*71bb428fSJakub Kicinski __u32 len = sizeof(info); 304*71bb428fSJakub Kicinski bool can_disasm = false; 305*71bb428fSJakub Kicinski unsigned int buf_size; 306*71bb428fSJakub Kicinski char *filepath = NULL; 307*71bb428fSJakub Kicinski bool opcodes = false; 308*71bb428fSJakub Kicinski unsigned char *buf; 309*71bb428fSJakub Kicinski __u32 *member_len; 310*71bb428fSJakub Kicinski __u64 *member_ptr; 311*71bb428fSJakub Kicinski ssize_t n; 312*71bb428fSJakub Kicinski int err; 313*71bb428fSJakub Kicinski int fd; 314*71bb428fSJakub Kicinski 315*71bb428fSJakub Kicinski if (is_prefix(*argv, "jited")) { 316*71bb428fSJakub Kicinski member_len = &info.jited_prog_len; 317*71bb428fSJakub Kicinski member_ptr = &info.jited_prog_insns; 318*71bb428fSJakub Kicinski can_disasm = true; 319*71bb428fSJakub Kicinski } else if (is_prefix(*argv, "xlated")) { 320*71bb428fSJakub Kicinski member_len = &info.xlated_prog_len; 321*71bb428fSJakub Kicinski member_ptr = &info.xlated_prog_insns; 322*71bb428fSJakub Kicinski } else { 323*71bb428fSJakub Kicinski err("expected 'xlated' or 'jited', got: %s\n", *argv); 324*71bb428fSJakub Kicinski return -1; 325*71bb428fSJakub Kicinski } 326*71bb428fSJakub Kicinski NEXT_ARG(); 327*71bb428fSJakub Kicinski 328*71bb428fSJakub Kicinski if (argc < 2) 329*71bb428fSJakub Kicinski usage(); 330*71bb428fSJakub Kicinski 331*71bb428fSJakub Kicinski fd = prog_parse_fd(&argc, &argv); 332*71bb428fSJakub Kicinski if (fd < 0) 333*71bb428fSJakub Kicinski return -1; 334*71bb428fSJakub Kicinski 335*71bb428fSJakub Kicinski if (is_prefix(*argv, "file")) { 336*71bb428fSJakub Kicinski NEXT_ARG(); 337*71bb428fSJakub Kicinski if (!argc) { 338*71bb428fSJakub Kicinski err("expected file path\n"); 339*71bb428fSJakub Kicinski return -1; 340*71bb428fSJakub Kicinski } 341*71bb428fSJakub Kicinski 342*71bb428fSJakub Kicinski filepath = *argv; 343*71bb428fSJakub Kicinski NEXT_ARG(); 344*71bb428fSJakub Kicinski } else if (is_prefix(*argv, "opcodes")) { 345*71bb428fSJakub Kicinski opcodes = true; 346*71bb428fSJakub Kicinski NEXT_ARG(); 347*71bb428fSJakub Kicinski } 348*71bb428fSJakub Kicinski 349*71bb428fSJakub Kicinski if (!filepath && !can_disasm) { 350*71bb428fSJakub Kicinski err("expected 'file' got %s\n", *argv); 351*71bb428fSJakub Kicinski return -1; 352*71bb428fSJakub Kicinski } 353*71bb428fSJakub Kicinski if (argc) { 354*71bb428fSJakub Kicinski usage(); 355*71bb428fSJakub Kicinski return -1; 356*71bb428fSJakub Kicinski } 357*71bb428fSJakub Kicinski 358*71bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 359*71bb428fSJakub Kicinski if (err) { 360*71bb428fSJakub Kicinski err("can't get prog info: %s\n", strerror(errno)); 361*71bb428fSJakub Kicinski return -1; 362*71bb428fSJakub Kicinski } 363*71bb428fSJakub Kicinski 364*71bb428fSJakub Kicinski if (!*member_len) { 365*71bb428fSJakub Kicinski info("no instructions returned\n"); 366*71bb428fSJakub Kicinski close(fd); 367*71bb428fSJakub Kicinski return 0; 368*71bb428fSJakub Kicinski } 369*71bb428fSJakub Kicinski 370*71bb428fSJakub Kicinski buf_size = *member_len; 371*71bb428fSJakub Kicinski 372*71bb428fSJakub Kicinski buf = malloc(buf_size); 373*71bb428fSJakub Kicinski if (!buf) { 374*71bb428fSJakub Kicinski err("mem alloc failed\n"); 375*71bb428fSJakub Kicinski close(fd); 376*71bb428fSJakub Kicinski return -1; 377*71bb428fSJakub Kicinski } 378*71bb428fSJakub Kicinski 379*71bb428fSJakub Kicinski memset(&info, 0, sizeof(info)); 380*71bb428fSJakub Kicinski 381*71bb428fSJakub Kicinski *member_ptr = ptr_to_u64(buf); 382*71bb428fSJakub Kicinski *member_len = buf_size; 383*71bb428fSJakub Kicinski 384*71bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 385*71bb428fSJakub Kicinski close(fd); 386*71bb428fSJakub Kicinski if (err) { 387*71bb428fSJakub Kicinski err("can't get prog info: %s\n", strerror(errno)); 388*71bb428fSJakub Kicinski goto err_free; 389*71bb428fSJakub Kicinski } 390*71bb428fSJakub Kicinski 391*71bb428fSJakub Kicinski if (*member_len > buf_size) { 392*71bb428fSJakub Kicinski info("too many instructions returned\n"); 393*71bb428fSJakub Kicinski goto err_free; 394*71bb428fSJakub Kicinski } 395*71bb428fSJakub Kicinski 396*71bb428fSJakub Kicinski if (filepath) { 397*71bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 398*71bb428fSJakub Kicinski if (fd < 0) { 399*71bb428fSJakub Kicinski err("can't open file %s: %s\n", filepath, 400*71bb428fSJakub Kicinski strerror(errno)); 401*71bb428fSJakub Kicinski goto err_free; 402*71bb428fSJakub Kicinski } 403*71bb428fSJakub Kicinski 404*71bb428fSJakub Kicinski n = write(fd, buf, *member_len); 405*71bb428fSJakub Kicinski close(fd); 406*71bb428fSJakub Kicinski if (n != *member_len) { 407*71bb428fSJakub Kicinski err("error writing output file: %s\n", 408*71bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 409*71bb428fSJakub Kicinski goto err_free; 410*71bb428fSJakub Kicinski } 411*71bb428fSJakub Kicinski } else { 412*71bb428fSJakub Kicinski disasm_print_insn(buf, *member_len, opcodes); 413*71bb428fSJakub Kicinski } 414*71bb428fSJakub Kicinski 415*71bb428fSJakub Kicinski free(buf); 416*71bb428fSJakub Kicinski 417*71bb428fSJakub Kicinski return 0; 418*71bb428fSJakub Kicinski 419*71bb428fSJakub Kicinski err_free: 420*71bb428fSJakub Kicinski free(buf); 421*71bb428fSJakub Kicinski return -1; 422*71bb428fSJakub Kicinski } 423*71bb428fSJakub Kicinski 424*71bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 425*71bb428fSJakub Kicinski { 426*71bb428fSJakub Kicinski return do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 427*71bb428fSJakub Kicinski } 428*71bb428fSJakub Kicinski 429*71bb428fSJakub Kicinski static int do_help(int argc, char **argv) 430*71bb428fSJakub Kicinski { 431*71bb428fSJakub Kicinski fprintf(stderr, 432*71bb428fSJakub Kicinski "Usage: %s %s show [PROG]\n" 433*71bb428fSJakub Kicinski " %s %s dump xlated PROG file FILE\n" 434*71bb428fSJakub Kicinski " %s %s dump jited PROG [file FILE] [opcodes]\n" 435*71bb428fSJakub Kicinski " %s %s pin PROG FILE\n" 436*71bb428fSJakub Kicinski " %s %s help\n" 437*71bb428fSJakub Kicinski "\n" 438*71bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 439*71bb428fSJakub Kicinski "", 440*71bb428fSJakub Kicinski bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 441*71bb428fSJakub Kicinski bin_name, argv[-2], bin_name, argv[-2]); 442*71bb428fSJakub Kicinski 443*71bb428fSJakub Kicinski return 0; 444*71bb428fSJakub Kicinski } 445*71bb428fSJakub Kicinski 446*71bb428fSJakub Kicinski static const struct cmd cmds[] = { 447*71bb428fSJakub Kicinski { "show", do_show }, 448*71bb428fSJakub Kicinski { "dump", do_dump }, 449*71bb428fSJakub Kicinski { "pin", do_pin }, 450*71bb428fSJakub Kicinski { 0 } 451*71bb428fSJakub Kicinski }; 452*71bb428fSJakub Kicinski 453*71bb428fSJakub Kicinski int do_prog(int argc, char **argv) 454*71bb428fSJakub Kicinski { 455*71bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 456*71bb428fSJakub Kicinski } 457