]>
Commit | Line | Data |
---|---|---|
71bb428f JK |
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> | |
c9c35995 | 38 | #include <stdarg.h> |
71bb428f JK |
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 | ||
49 | #include "main.h" | |
c9c35995 | 50 | #include "disasm.h" |
71bb428f JK |
51 | |
52 | static const char * const prog_type_name[] = { | |
53 | [BPF_PROG_TYPE_UNSPEC] = "unspec", | |
54 | [BPF_PROG_TYPE_SOCKET_FILTER] = "socket_filter", | |
55 | [BPF_PROG_TYPE_KPROBE] = "kprobe", | |
56 | [BPF_PROG_TYPE_SCHED_CLS] = "sched_cls", | |
57 | [BPF_PROG_TYPE_SCHED_ACT] = "sched_act", | |
58 | [BPF_PROG_TYPE_TRACEPOINT] = "tracepoint", | |
59 | [BPF_PROG_TYPE_XDP] = "xdp", | |
60 | [BPF_PROG_TYPE_PERF_EVENT] = "perf_event", | |
61 | [BPF_PROG_TYPE_CGROUP_SKB] = "cgroup_skb", | |
62 | [BPF_PROG_TYPE_CGROUP_SOCK] = "cgroup_sock", | |
63 | [BPF_PROG_TYPE_LWT_IN] = "lwt_in", | |
64 | [BPF_PROG_TYPE_LWT_OUT] = "lwt_out", | |
65 | [BPF_PROG_TYPE_LWT_XMIT] = "lwt_xmit", | |
66 | [BPF_PROG_TYPE_SOCK_OPS] = "sock_ops", | |
67 | [BPF_PROG_TYPE_SK_SKB] = "sk_skb", | |
68 | }; | |
69 | ||
70 | static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) | |
71 | { | |
72 | struct timespec real_time_ts, boot_time_ts; | |
73 | time_t wallclock_secs; | |
74 | struct tm load_tm; | |
75 | ||
76 | buf[--size] = '\0'; | |
77 | ||
78 | if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || | |
79 | clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { | |
80 | perror("Can't read clocks"); | |
81 | snprintf(buf, size, "%llu", nsecs / 1000000000); | |
82 | return; | |
83 | } | |
84 | ||
85 | wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + | |
86 | nsecs / 1000000000; | |
87 | ||
88 | if (!localtime_r(&wallclock_secs, &load_tm)) { | |
89 | snprintf(buf, size, "%llu", nsecs / 1000000000); | |
90 | return; | |
91 | } | |
92 | ||
93 | strftime(buf, size, "%b %d/%H:%M", &load_tm); | |
94 | } | |
95 | ||
96 | static int prog_fd_by_tag(unsigned char *tag) | |
97 | { | |
98 | struct bpf_prog_info info = {}; | |
99 | __u32 len = sizeof(info); | |
100 | unsigned int id = 0; | |
101 | int err; | |
102 | int fd; | |
103 | ||
104 | while (true) { | |
105 | err = bpf_prog_get_next_id(id, &id); | |
106 | if (err) { | |
9a5ab8bf | 107 | p_err("%s", strerror(errno)); |
71bb428f JK |
108 | return -1; |
109 | } | |
110 | ||
111 | fd = bpf_prog_get_fd_by_id(id); | |
112 | if (fd < 0) { | |
9a5ab8bf QM |
113 | p_err("can't get prog by id (%u): %s", |
114 | id, strerror(errno)); | |
71bb428f JK |
115 | return -1; |
116 | } | |
117 | ||
118 | err = bpf_obj_get_info_by_fd(fd, &info, &len); | |
119 | if (err) { | |
9a5ab8bf QM |
120 | p_err("can't get prog info (%u): %s", |
121 | id, strerror(errno)); | |
71bb428f JK |
122 | close(fd); |
123 | return -1; | |
124 | } | |
125 | ||
126 | if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) | |
127 | return fd; | |
128 | ||
129 | close(fd); | |
130 | } | |
131 | } | |
132 | ||
133 | int prog_parse_fd(int *argc, char ***argv) | |
134 | { | |
135 | int fd; | |
136 | ||
137 | if (is_prefix(**argv, "id")) { | |
138 | unsigned int id; | |
139 | char *endptr; | |
140 | ||
141 | NEXT_ARGP(); | |
142 | ||
143 | id = strtoul(**argv, &endptr, 0); | |
144 | if (*endptr) { | |
9a5ab8bf | 145 | p_err("can't parse %s as ID", **argv); |
71bb428f JK |
146 | return -1; |
147 | } | |
148 | NEXT_ARGP(); | |
149 | ||
150 | fd = bpf_prog_get_fd_by_id(id); | |
151 | if (fd < 0) | |
9a5ab8bf | 152 | p_err("get by id (%u): %s", id, strerror(errno)); |
71bb428f JK |
153 | return fd; |
154 | } else if (is_prefix(**argv, "tag")) { | |
155 | unsigned char tag[BPF_TAG_SIZE]; | |
156 | ||
157 | NEXT_ARGP(); | |
158 | ||
159 | if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, | |
160 | tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) | |
161 | != BPF_TAG_SIZE) { | |
9a5ab8bf | 162 | p_err("can't parse tag"); |
71bb428f JK |
163 | return -1; |
164 | } | |
165 | NEXT_ARGP(); | |
166 | ||
167 | return prog_fd_by_tag(tag); | |
168 | } else if (is_prefix(**argv, "pinned")) { | |
169 | char *path; | |
170 | ||
171 | NEXT_ARGP(); | |
172 | ||
173 | path = **argv; | |
174 | NEXT_ARGP(); | |
175 | ||
176 | return open_obj_pinned_any(path, BPF_OBJ_PROG); | |
177 | } | |
178 | ||
9a5ab8bf | 179 | p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); |
71bb428f JK |
180 | return -1; |
181 | } | |
182 | ||
183 | static void show_prog_maps(int fd, u32 num_maps) | |
184 | { | |
185 | struct bpf_prog_info info = {}; | |
186 | __u32 len = sizeof(info); | |
187 | __u32 map_ids[num_maps]; | |
188 | unsigned int i; | |
189 | int err; | |
190 | ||
191 | info.nr_map_ids = num_maps; | |
192 | info.map_ids = ptr_to_u64(map_ids); | |
193 | ||
194 | err = bpf_obj_get_info_by_fd(fd, &info, &len); | |
195 | if (err || !info.nr_map_ids) | |
196 | return; | |
197 | ||
743cc665 QM |
198 | if (json_output) { |
199 | jsonw_name(json_wtr, "map_ids"); | |
200 | jsonw_start_array(json_wtr); | |
201 | for (i = 0; i < info.nr_map_ids; i++) | |
202 | jsonw_uint(json_wtr, map_ids[i]); | |
203 | jsonw_end_array(json_wtr); | |
204 | } else { | |
205 | printf(" map_ids "); | |
206 | for (i = 0; i < info.nr_map_ids; i++) | |
207 | printf("%u%s", map_ids[i], | |
208 | i == info.nr_map_ids - 1 ? "" : ","); | |
209 | } | |
71bb428f JK |
210 | } |
211 | ||
743cc665 | 212 | static void print_prog_json(struct bpf_prog_info *info, int fd) |
71bb428f | 213 | { |
71bb428f | 214 | char *memlock; |
71bb428f | 215 | |
743cc665 QM |
216 | jsonw_start_object(json_wtr); |
217 | jsonw_uint_field(json_wtr, "id", info->id); | |
218 | if (info->type < ARRAY_SIZE(prog_type_name)) | |
219 | jsonw_string_field(json_wtr, "type", | |
220 | prog_type_name[info->type]); | |
221 | else | |
222 | jsonw_uint_field(json_wtr, "type", info->type); | |
223 | ||
224 | if (*info->name) | |
225 | jsonw_string_field(json_wtr, "name", info->name); | |
226 | ||
227 | jsonw_name(json_wtr, "tag"); | |
228 | jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", | |
229 | info->tag[0], info->tag[1], info->tag[2], info->tag[3], | |
230 | info->tag[4], info->tag[5], info->tag[6], info->tag[7]); | |
231 | ||
232 | if (info->load_time) { | |
233 | char buf[32]; | |
234 | ||
235 | print_boot_time(info->load_time, buf, sizeof(buf)); | |
236 | ||
237 | /* Piggy back on load_time, since 0 uid is a valid one */ | |
238 | jsonw_string_field(json_wtr, "loaded_at", buf); | |
239 | jsonw_uint_field(json_wtr, "uid", info->created_by_uid); | |
240 | } | |
241 | ||
242 | jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); | |
243 | ||
244 | if (info->jited_prog_len) { | |
245 | jsonw_bool_field(json_wtr, "jited", true); | |
246 | jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); | |
247 | } else { | |
248 | jsonw_bool_field(json_wtr, "jited", false); | |
71bb428f JK |
249 | } |
250 | ||
743cc665 QM |
251 | memlock = get_fdinfo(fd, "memlock"); |
252 | if (memlock) | |
253 | jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); | |
254 | free(memlock); | |
255 | ||
256 | if (info->nr_map_ids) | |
257 | show_prog_maps(fd, info->nr_map_ids); | |
258 | ||
259 | jsonw_end_object(json_wtr); | |
260 | } | |
261 | ||
262 | static void print_prog_plain(struct bpf_prog_info *info, int fd) | |
263 | { | |
264 | char *memlock; | |
265 | ||
266 | printf("%u: ", info->id); | |
267 | if (info->type < ARRAY_SIZE(prog_type_name)) | |
268 | printf("%s ", prog_type_name[info->type]); | |
71bb428f | 269 | else |
743cc665 | 270 | printf("type %u ", info->type); |
71bb428f | 271 | |
743cc665 QM |
272 | if (*info->name) |
273 | printf("name %s ", info->name); | |
71bb428f JK |
274 | |
275 | printf("tag "); | |
743cc665 | 276 | fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); |
71bb428f JK |
277 | printf("\n"); |
278 | ||
743cc665 | 279 | if (info->load_time) { |
71bb428f JK |
280 | char buf[32]; |
281 | ||
743cc665 | 282 | print_boot_time(info->load_time, buf, sizeof(buf)); |
71bb428f JK |
283 | |
284 | /* Piggy back on load_time, since 0 uid is a valid one */ | |
743cc665 | 285 | printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); |
71bb428f JK |
286 | } |
287 | ||
743cc665 | 288 | printf("\txlated %uB", info->xlated_prog_len); |
71bb428f | 289 | |
743cc665 QM |
290 | if (info->jited_prog_len) |
291 | printf(" jited %uB", info->jited_prog_len); | |
71bb428f JK |
292 | else |
293 | printf(" not jited"); | |
294 | ||
295 | memlock = get_fdinfo(fd, "memlock"); | |
296 | if (memlock) | |
297 | printf(" memlock %sB", memlock); | |
298 | free(memlock); | |
299 | ||
743cc665 QM |
300 | if (info->nr_map_ids) |
301 | show_prog_maps(fd, info->nr_map_ids); | |
71bb428f JK |
302 | |
303 | printf("\n"); | |
743cc665 QM |
304 | } |
305 | ||
306 | static int show_prog(int fd) | |
307 | { | |
308 | struct bpf_prog_info info = {}; | |
309 | __u32 len = sizeof(info); | |
310 | int err; | |
311 | ||
312 | err = bpf_obj_get_info_by_fd(fd, &info, &len); | |
313 | if (err) { | |
9a5ab8bf | 314 | p_err("can't get prog info: %s", strerror(errno)); |
743cc665 QM |
315 | return -1; |
316 | } | |
317 | ||
318 | if (json_output) | |
319 | print_prog_json(&info, fd); | |
320 | else | |
321 | print_prog_plain(&info, fd); | |
71bb428f JK |
322 | |
323 | return 0; | |
324 | } | |
325 | ||
326 | static int do_show(int argc, char **argv) | |
743cc665 QM |
327 | { |
328 | __u32 id = 0; | |
71bb428f JK |
329 | int err; |
330 | int fd; | |
331 | ||
332 | if (argc == 2) { | |
333 | fd = prog_parse_fd(&argc, &argv); | |
334 | if (fd < 0) | |
335 | return -1; | |
336 | ||
337 | return show_prog(fd); | |
338 | } | |
339 | ||
340 | if (argc) | |
341 | return BAD_ARG(); | |
342 | ||
743cc665 QM |
343 | if (json_output) |
344 | jsonw_start_array(json_wtr); | |
71bb428f JK |
345 | while (true) { |
346 | err = bpf_prog_get_next_id(id, &id); | |
347 | if (err) { | |
1739c26d QM |
348 | if (errno == ENOENT) { |
349 | err = 0; | |
71bb428f | 350 | break; |
1739c26d | 351 | } |
9a5ab8bf QM |
352 | p_err("can't get next program: %s%s", strerror(errno), |
353 | errno == EINVAL ? " -- kernel too old?" : ""); | |
743cc665 QM |
354 | err = -1; |
355 | break; | |
71bb428f JK |
356 | } |
357 | ||
358 | fd = bpf_prog_get_fd_by_id(id); | |
359 | if (fd < 0) { | |
9a5ab8bf QM |
360 | p_err("can't get prog by id (%u): %s", |
361 | id, strerror(errno)); | |
743cc665 QM |
362 | err = -1; |
363 | break; | |
71bb428f JK |
364 | } |
365 | ||
366 | err = show_prog(fd); | |
367 | close(fd); | |
368 | if (err) | |
743cc665 | 369 | break; |
71bb428f JK |
370 | } |
371 | ||
743cc665 QM |
372 | if (json_output) |
373 | jsonw_end_array(json_wtr); | |
374 | ||
375 | return err; | |
71bb428f JK |
376 | } |
377 | ||
c9c35995 JK |
378 | static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...) |
379 | { | |
380 | va_list args; | |
381 | ||
382 | va_start(args, fmt); | |
383 | vprintf(fmt, args); | |
384 | va_end(args); | |
385 | } | |
386 | ||
f05e2c32 | 387 | static void dump_xlated_plain(void *buf, unsigned int len, bool opcodes) |
c9c35995 JK |
388 | { |
389 | struct bpf_insn *insn = buf; | |
9e2308c1 | 390 | bool double_insn = false; |
c9c35995 JK |
391 | unsigned int i; |
392 | ||
393 | for (i = 0; i < len / sizeof(*insn); i++) { | |
9e2308c1 QM |
394 | if (double_insn) { |
395 | double_insn = false; | |
396 | continue; | |
397 | } | |
398 | ||
399 | double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); | |
400 | ||
c9c35995 JK |
401 | printf("% 4d: ", i); |
402 | print_bpf_insn(print_insn, NULL, insn + i, true); | |
403 | ||
404 | if (opcodes) { | |
405 | printf(" "); | |
9cbe1f58 | 406 | fprint_hex(stdout, insn + i, 8, " "); |
9e2308c1 QM |
407 | if (double_insn && i < len - 1) { |
408 | printf(" "); | |
409 | fprint_hex(stdout, insn + i + 1, 8, " "); | |
410 | } | |
c9c35995 JK |
411 | printf("\n"); |
412 | } | |
c9c35995 JK |
413 | } |
414 | } | |
415 | ||
f05e2c32 QM |
416 | static void print_insn_json(struct bpf_verifier_env *env, const char *fmt, ...) |
417 | { | |
418 | unsigned int l = strlen(fmt); | |
419 | char chomped_fmt[l]; | |
420 | va_list args; | |
421 | ||
422 | va_start(args, fmt); | |
423 | if (l > 0) { | |
424 | strncpy(chomped_fmt, fmt, l - 1); | |
425 | chomped_fmt[l - 1] = '\0'; | |
426 | } | |
427 | jsonw_vprintf_enquote(json_wtr, chomped_fmt, args); | |
428 | va_end(args); | |
429 | } | |
430 | ||
431 | static void dump_xlated_json(void *buf, unsigned int len, bool opcodes) | |
432 | { | |
433 | struct bpf_insn *insn = buf; | |
434 | bool double_insn = false; | |
435 | unsigned int i; | |
436 | ||
437 | jsonw_start_array(json_wtr); | |
438 | for (i = 0; i < len / sizeof(*insn); i++) { | |
439 | if (double_insn) { | |
440 | double_insn = false; | |
441 | continue; | |
442 | } | |
443 | double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); | |
444 | ||
445 | jsonw_start_object(json_wtr); | |
446 | jsonw_name(json_wtr, "disasm"); | |
447 | print_bpf_insn(print_insn_json, NULL, insn + i, true); | |
448 | ||
449 | if (opcodes) { | |
450 | jsonw_name(json_wtr, "opcodes"); | |
451 | jsonw_start_object(json_wtr); | |
452 | ||
453 | jsonw_name(json_wtr, "code"); | |
454 | jsonw_printf(json_wtr, "\"0x%02hhx\"", insn[i].code); | |
455 | ||
456 | jsonw_name(json_wtr, "src_reg"); | |
457 | jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].src_reg); | |
458 | ||
459 | jsonw_name(json_wtr, "dst_reg"); | |
460 | jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].dst_reg); | |
461 | ||
462 | jsonw_name(json_wtr, "off"); | |
463 | print_hex_data_json((uint8_t *)(&insn[i].off), 2); | |
464 | ||
465 | jsonw_name(json_wtr, "imm"); | |
466 | if (double_insn && i < len - 1) | |
467 | print_hex_data_json((uint8_t *)(&insn[i].imm), | |
468 | 12); | |
469 | else | |
470 | print_hex_data_json((uint8_t *)(&insn[i].imm), | |
471 | 4); | |
472 | jsonw_end_object(json_wtr); | |
473 | } | |
474 | jsonw_end_object(json_wtr); | |
475 | } | |
476 | jsonw_end_array(json_wtr); | |
477 | } | |
478 | ||
71bb428f JK |
479 | static int do_dump(int argc, char **argv) |
480 | { | |
481 | struct bpf_prog_info info = {}; | |
482 | __u32 len = sizeof(info); | |
71bb428f JK |
483 | unsigned int buf_size; |
484 | char *filepath = NULL; | |
485 | bool opcodes = false; | |
486 | unsigned char *buf; | |
487 | __u32 *member_len; | |
488 | __u64 *member_ptr; | |
489 | ssize_t n; | |
490 | int err; | |
491 | int fd; | |
492 | ||
493 | if (is_prefix(*argv, "jited")) { | |
494 | member_len = &info.jited_prog_len; | |
495 | member_ptr = &info.jited_prog_insns; | |
71bb428f JK |
496 | } else if (is_prefix(*argv, "xlated")) { |
497 | member_len = &info.xlated_prog_len; | |
498 | member_ptr = &info.xlated_prog_insns; | |
499 | } else { | |
9a5ab8bf | 500 | p_err("expected 'xlated' or 'jited', got: %s", *argv); |
71bb428f JK |
501 | return -1; |
502 | } | |
503 | NEXT_ARG(); | |
504 | ||
505 | if (argc < 2) | |
506 | usage(); | |
507 | ||
508 | fd = prog_parse_fd(&argc, &argv); | |
509 | if (fd < 0) | |
510 | return -1; | |
511 | ||
512 | if (is_prefix(*argv, "file")) { | |
513 | NEXT_ARG(); | |
514 | if (!argc) { | |
9a5ab8bf | 515 | p_err("expected file path"); |
71bb428f JK |
516 | return -1; |
517 | } | |
518 | ||
519 | filepath = *argv; | |
520 | NEXT_ARG(); | |
521 | } else if (is_prefix(*argv, "opcodes")) { | |
522 | opcodes = true; | |
523 | NEXT_ARG(); | |
524 | } | |
525 | ||
71bb428f JK |
526 | if (argc) { |
527 | usage(); | |
528 | return -1; | |
529 | } | |
530 | ||
531 | err = bpf_obj_get_info_by_fd(fd, &info, &len); | |
532 | if (err) { | |
9a5ab8bf | 533 | p_err("can't get prog info: %s", strerror(errno)); |
71bb428f JK |
534 | return -1; |
535 | } | |
536 | ||
537 | if (!*member_len) { | |
9a5ab8bf | 538 | p_info("no instructions returned"); |
71bb428f JK |
539 | close(fd); |
540 | return 0; | |
541 | } | |
542 | ||
543 | buf_size = *member_len; | |
544 | ||
545 | buf = malloc(buf_size); | |
546 | if (!buf) { | |
9a5ab8bf | 547 | p_err("mem alloc failed"); |
71bb428f JK |
548 | close(fd); |
549 | return -1; | |
550 | } | |
551 | ||
552 | memset(&info, 0, sizeof(info)); | |
553 | ||
554 | *member_ptr = ptr_to_u64(buf); | |
555 | *member_len = buf_size; | |
556 | ||
557 | err = bpf_obj_get_info_by_fd(fd, &info, &len); | |
558 | close(fd); | |
559 | if (err) { | |
9a5ab8bf | 560 | p_err("can't get prog info: %s", strerror(errno)); |
71bb428f JK |
561 | goto err_free; |
562 | } | |
563 | ||
564 | if (*member_len > buf_size) { | |
9a5ab8bf | 565 | p_err("too many instructions returned"); |
71bb428f JK |
566 | goto err_free; |
567 | } | |
568 | ||
569 | if (filepath) { | |
570 | fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); | |
571 | if (fd < 0) { | |
9a5ab8bf QM |
572 | p_err("can't open file %s: %s", filepath, |
573 | strerror(errno)); | |
71bb428f JK |
574 | goto err_free; |
575 | } | |
576 | ||
577 | n = write(fd, buf, *member_len); | |
578 | close(fd); | |
579 | if (n != *member_len) { | |
9a5ab8bf QM |
580 | p_err("error writing output file: %s", |
581 | n < 0 ? strerror(errno) : "short write"); | |
71bb428f JK |
582 | goto err_free; |
583 | } | |
584 | } else { | |
c9c35995 JK |
585 | if (member_len == &info.jited_prog_len) |
586 | disasm_print_insn(buf, *member_len, opcodes); | |
587 | else | |
f05e2c32 QM |
588 | if (json_output) |
589 | dump_xlated_json(buf, *member_len, opcodes); | |
590 | else | |
591 | dump_xlated_plain(buf, *member_len, opcodes); | |
71bb428f JK |
592 | } |
593 | ||
594 | free(buf); | |
595 | ||
596 | return 0; | |
597 | ||
598 | err_free: | |
599 | free(buf); | |
600 | return -1; | |
601 | } | |
602 | ||
603 | static int do_pin(int argc, char **argv) | |
604 | { | |
004b45c0 QM |
605 | int err; |
606 | ||
607 | err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); | |
608 | if (!err && json_output) | |
609 | jsonw_null(json_wtr); | |
610 | return err; | |
71bb428f JK |
611 | } |
612 | ||
613 | static int do_help(int argc, char **argv) | |
614 | { | |
004b45c0 QM |
615 | if (json_output) { |
616 | jsonw_null(json_wtr); | |
617 | return 0; | |
618 | } | |
619 | ||
71bb428f JK |
620 | fprintf(stderr, |
621 | "Usage: %s %s show [PROG]\n" | |
8dfbc6d1 QM |
622 | " %s %s dump xlated PROG [{ file FILE | opcodes }]\n" |
623 | " %s %s dump jited PROG [{ file FILE | opcodes }]\n" | |
71bb428f JK |
624 | " %s %s pin PROG FILE\n" |
625 | " %s %s help\n" | |
626 | "\n" | |
627 | " " HELP_SPEC_PROGRAM "\n" | |
628 | "", | |
629 | bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], | |
630 | bin_name, argv[-2], bin_name, argv[-2]); | |
631 | ||
632 | return 0; | |
633 | } | |
634 | ||
635 | static const struct cmd cmds[] = { | |
636 | { "show", do_show }, | |
9f606179 | 637 | { "help", do_help }, |
71bb428f JK |
638 | { "dump", do_dump }, |
639 | { "pin", do_pin }, | |
640 | { 0 } | |
641 | }; | |
642 | ||
643 | int do_prog(int argc, char **argv) | |
644 | { | |
645 | return cmd_select(cmds, argc, argv, do_help); | |
646 | } |