1 /* 2 * Copyright (C) 2017-2018 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 #include <assert.h> 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <stdbool.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 #include <sys/types.h> 43 #include <sys/stat.h> 44 45 #include <bpf.h> 46 47 #include "main.h" 48 49 static const char * const map_type_name[] = { 50 [BPF_MAP_TYPE_UNSPEC] = "unspec", 51 [BPF_MAP_TYPE_HASH] = "hash", 52 [BPF_MAP_TYPE_ARRAY] = "array", 53 [BPF_MAP_TYPE_PROG_ARRAY] = "prog_array", 54 [BPF_MAP_TYPE_PERF_EVENT_ARRAY] = "perf_event_array", 55 [BPF_MAP_TYPE_PERCPU_HASH] = "percpu_hash", 56 [BPF_MAP_TYPE_PERCPU_ARRAY] = "percpu_array", 57 [BPF_MAP_TYPE_STACK_TRACE] = "stack_trace", 58 [BPF_MAP_TYPE_CGROUP_ARRAY] = "cgroup_array", 59 [BPF_MAP_TYPE_LRU_HASH] = "lru_hash", 60 [BPF_MAP_TYPE_LRU_PERCPU_HASH] = "lru_percpu_hash", 61 [BPF_MAP_TYPE_LPM_TRIE] = "lpm_trie", 62 [BPF_MAP_TYPE_ARRAY_OF_MAPS] = "array_of_maps", 63 [BPF_MAP_TYPE_HASH_OF_MAPS] = "hash_of_maps", 64 [BPF_MAP_TYPE_DEVMAP] = "devmap", 65 [BPF_MAP_TYPE_SOCKMAP] = "sockmap", 66 [BPF_MAP_TYPE_CPUMAP] = "cpumap", 67 [BPF_MAP_TYPE_SOCKHASH] = "sockhash", 68 }; 69 70 static bool map_is_per_cpu(__u32 type) 71 { 72 return type == BPF_MAP_TYPE_PERCPU_HASH || 73 type == BPF_MAP_TYPE_PERCPU_ARRAY || 74 type == BPF_MAP_TYPE_LRU_PERCPU_HASH; 75 } 76 77 static bool map_is_map_of_maps(__u32 type) 78 { 79 return type == BPF_MAP_TYPE_ARRAY_OF_MAPS || 80 type == BPF_MAP_TYPE_HASH_OF_MAPS; 81 } 82 83 static bool map_is_map_of_progs(__u32 type) 84 { 85 return type == BPF_MAP_TYPE_PROG_ARRAY; 86 } 87 88 static void *alloc_value(struct bpf_map_info *info) 89 { 90 if (map_is_per_cpu(info->type)) 91 return malloc(info->value_size * get_possible_cpus()); 92 else 93 return malloc(info->value_size); 94 } 95 96 int map_parse_fd(int *argc, char ***argv) 97 { 98 int fd; 99 100 if (is_prefix(**argv, "id")) { 101 unsigned int id; 102 char *endptr; 103 104 NEXT_ARGP(); 105 106 id = strtoul(**argv, &endptr, 0); 107 if (*endptr) { 108 p_err("can't parse %s as ID", **argv); 109 return -1; 110 } 111 NEXT_ARGP(); 112 113 fd = bpf_map_get_fd_by_id(id); 114 if (fd < 0) 115 p_err("get map by id (%u): %s", id, strerror(errno)); 116 return fd; 117 } else if (is_prefix(**argv, "pinned")) { 118 char *path; 119 120 NEXT_ARGP(); 121 122 path = **argv; 123 NEXT_ARGP(); 124 125 return open_obj_pinned_any(path, BPF_OBJ_MAP); 126 } 127 128 p_err("expected 'id' or 'pinned', got: '%s'?", **argv); 129 return -1; 130 } 131 132 int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len) 133 { 134 int err; 135 int fd; 136 137 fd = map_parse_fd(argc, argv); 138 if (fd < 0) 139 return -1; 140 141 err = bpf_obj_get_info_by_fd(fd, info, info_len); 142 if (err) { 143 p_err("can't get map info: %s", strerror(errno)); 144 close(fd); 145 return err; 146 } 147 148 return fd; 149 } 150 151 static void print_entry_json(struct bpf_map_info *info, unsigned char *key, 152 unsigned char *value) 153 { 154 jsonw_start_object(json_wtr); 155 156 if (!map_is_per_cpu(info->type)) { 157 jsonw_name(json_wtr, "key"); 158 print_hex_data_json(key, info->key_size); 159 jsonw_name(json_wtr, "value"); 160 print_hex_data_json(value, info->value_size); 161 } else { 162 unsigned int i, n; 163 164 n = get_possible_cpus(); 165 166 jsonw_name(json_wtr, "key"); 167 print_hex_data_json(key, info->key_size); 168 169 jsonw_name(json_wtr, "values"); 170 jsonw_start_array(json_wtr); 171 for (i = 0; i < n; i++) { 172 jsonw_start_object(json_wtr); 173 174 jsonw_int_field(json_wtr, "cpu", i); 175 176 jsonw_name(json_wtr, "value"); 177 print_hex_data_json(value + i * info->value_size, 178 info->value_size); 179 180 jsonw_end_object(json_wtr); 181 } 182 jsonw_end_array(json_wtr); 183 } 184 185 jsonw_end_object(json_wtr); 186 } 187 188 static void print_entry_plain(struct bpf_map_info *info, unsigned char *key, 189 unsigned char *value) 190 { 191 if (!map_is_per_cpu(info->type)) { 192 bool single_line, break_names; 193 194 break_names = info->key_size > 16 || info->value_size > 16; 195 single_line = info->key_size + info->value_size <= 24 && 196 !break_names; 197 198 printf("key:%c", break_names ? '\n' : ' '); 199 fprint_hex(stdout, key, info->key_size, " "); 200 201 printf(single_line ? " " : "\n"); 202 203 printf("value:%c", break_names ? '\n' : ' '); 204 fprint_hex(stdout, value, info->value_size, " "); 205 206 printf("\n"); 207 } else { 208 unsigned int i, n; 209 210 n = get_possible_cpus(); 211 212 printf("key:\n"); 213 fprint_hex(stdout, key, info->key_size, " "); 214 printf("\n"); 215 for (i = 0; i < n; i++) { 216 printf("value (CPU %02d):%c", 217 i, info->value_size > 16 ? '\n' : ' '); 218 fprint_hex(stdout, value + i * info->value_size, 219 info->value_size, " "); 220 printf("\n"); 221 } 222 } 223 } 224 225 static char **parse_bytes(char **argv, const char *name, unsigned char *val, 226 unsigned int n) 227 { 228 unsigned int i = 0, base = 0; 229 char *endptr; 230 231 if (is_prefix(*argv, "hex")) { 232 base = 16; 233 argv++; 234 } 235 236 while (i < n && argv[i]) { 237 val[i] = strtoul(argv[i], &endptr, base); 238 if (*endptr) { 239 p_err("error parsing byte: %s", argv[i]); 240 return NULL; 241 } 242 i++; 243 } 244 245 if (i != n) { 246 p_err("%s expected %d bytes got %d", name, n, i); 247 return NULL; 248 } 249 250 return argv + i; 251 } 252 253 static int parse_elem(char **argv, struct bpf_map_info *info, 254 void *key, void *value, __u32 key_size, __u32 value_size, 255 __u32 *flags, __u32 **value_fd) 256 { 257 if (!*argv) { 258 if (!key && !value) 259 return 0; 260 p_err("did not find %s", key ? "key" : "value"); 261 return -1; 262 } 263 264 if (is_prefix(*argv, "key")) { 265 if (!key) { 266 if (key_size) 267 p_err("duplicate key"); 268 else 269 p_err("unnecessary key"); 270 return -1; 271 } 272 273 argv = parse_bytes(argv + 1, "key", key, key_size); 274 if (!argv) 275 return -1; 276 277 return parse_elem(argv, info, NULL, value, key_size, value_size, 278 flags, value_fd); 279 } else if (is_prefix(*argv, "value")) { 280 int fd; 281 282 if (!value) { 283 if (value_size) 284 p_err("duplicate value"); 285 else 286 p_err("unnecessary value"); 287 return -1; 288 } 289 290 argv++; 291 292 if (map_is_map_of_maps(info->type)) { 293 int argc = 2; 294 295 if (value_size != 4) { 296 p_err("value smaller than 4B for map in map?"); 297 return -1; 298 } 299 if (!argv[0] || !argv[1]) { 300 p_err("not enough value arguments for map in map"); 301 return -1; 302 } 303 304 fd = map_parse_fd(&argc, &argv); 305 if (fd < 0) 306 return -1; 307 308 *value_fd = value; 309 **value_fd = fd; 310 } else if (map_is_map_of_progs(info->type)) { 311 int argc = 2; 312 313 if (value_size != 4) { 314 p_err("value smaller than 4B for map of progs?"); 315 return -1; 316 } 317 if (!argv[0] || !argv[1]) { 318 p_err("not enough value arguments for map of progs"); 319 return -1; 320 } 321 322 fd = prog_parse_fd(&argc, &argv); 323 if (fd < 0) 324 return -1; 325 326 *value_fd = value; 327 **value_fd = fd; 328 } else { 329 argv = parse_bytes(argv, "value", value, value_size); 330 if (!argv) 331 return -1; 332 } 333 334 return parse_elem(argv, info, key, NULL, key_size, value_size, 335 flags, NULL); 336 } else if (is_prefix(*argv, "any") || is_prefix(*argv, "noexist") || 337 is_prefix(*argv, "exist")) { 338 if (!flags) { 339 p_err("flags specified multiple times: %s", *argv); 340 return -1; 341 } 342 343 if (is_prefix(*argv, "any")) 344 *flags = BPF_ANY; 345 else if (is_prefix(*argv, "noexist")) 346 *flags = BPF_NOEXIST; 347 else if (is_prefix(*argv, "exist")) 348 *flags = BPF_EXIST; 349 350 return parse_elem(argv + 1, info, key, value, key_size, 351 value_size, NULL, value_fd); 352 } 353 354 p_err("expected key or value, got: %s", *argv); 355 return -1; 356 } 357 358 static int show_map_close_json(int fd, struct bpf_map_info *info) 359 { 360 char *memlock; 361 362 memlock = get_fdinfo(fd, "memlock"); 363 close(fd); 364 365 jsonw_start_object(json_wtr); 366 367 jsonw_uint_field(json_wtr, "id", info->id); 368 if (info->type < ARRAY_SIZE(map_type_name)) 369 jsonw_string_field(json_wtr, "type", 370 map_type_name[info->type]); 371 else 372 jsonw_uint_field(json_wtr, "type", info->type); 373 374 if (*info->name) 375 jsonw_string_field(json_wtr, "name", info->name); 376 377 jsonw_name(json_wtr, "flags"); 378 jsonw_printf(json_wtr, "%d", info->map_flags); 379 380 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 381 382 jsonw_uint_field(json_wtr, "bytes_key", info->key_size); 383 jsonw_uint_field(json_wtr, "bytes_value", info->value_size); 384 jsonw_uint_field(json_wtr, "max_entries", info->max_entries); 385 386 if (memlock) 387 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 388 free(memlock); 389 390 if (!hash_empty(map_table.table)) { 391 struct pinned_obj *obj; 392 393 jsonw_name(json_wtr, "pinned"); 394 jsonw_start_array(json_wtr); 395 hash_for_each_possible(map_table.table, obj, hash, info->id) { 396 if (obj->id == info->id) 397 jsonw_string(json_wtr, obj->path); 398 } 399 jsonw_end_array(json_wtr); 400 } 401 402 jsonw_end_object(json_wtr); 403 404 return 0; 405 } 406 407 static int show_map_close_plain(int fd, struct bpf_map_info *info) 408 { 409 char *memlock; 410 411 memlock = get_fdinfo(fd, "memlock"); 412 close(fd); 413 414 printf("%u: ", info->id); 415 if (info->type < ARRAY_SIZE(map_type_name)) 416 printf("%s ", map_type_name[info->type]); 417 else 418 printf("type %u ", info->type); 419 420 if (*info->name) 421 printf("name %s ", info->name); 422 423 printf("flags 0x%x", info->map_flags); 424 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 425 printf("\n"); 426 printf("\tkey %uB value %uB max_entries %u", 427 info->key_size, info->value_size, info->max_entries); 428 429 if (memlock) 430 printf(" memlock %sB", memlock); 431 free(memlock); 432 433 printf("\n"); 434 if (!hash_empty(map_table.table)) { 435 struct pinned_obj *obj; 436 437 hash_for_each_possible(map_table.table, obj, hash, info->id) { 438 if (obj->id == info->id) 439 printf("\tpinned %s\n", obj->path); 440 } 441 } 442 return 0; 443 } 444 445 static int do_show(int argc, char **argv) 446 { 447 struct bpf_map_info info = {}; 448 __u32 len = sizeof(info); 449 __u32 id = 0; 450 int err; 451 int fd; 452 453 if (show_pinned) 454 build_pinned_obj_table(&map_table, BPF_OBJ_MAP); 455 456 if (argc == 2) { 457 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 458 if (fd < 0) 459 return -1; 460 461 if (json_output) 462 return show_map_close_json(fd, &info); 463 else 464 return show_map_close_plain(fd, &info); 465 } 466 467 if (argc) 468 return BAD_ARG(); 469 470 if (json_output) 471 jsonw_start_array(json_wtr); 472 while (true) { 473 err = bpf_map_get_next_id(id, &id); 474 if (err) { 475 if (errno == ENOENT) 476 break; 477 p_err("can't get next map: %s%s", strerror(errno), 478 errno == EINVAL ? " -- kernel too old?" : ""); 479 break; 480 } 481 482 fd = bpf_map_get_fd_by_id(id); 483 if (fd < 0) { 484 if (errno == ENOENT) 485 continue; 486 p_err("can't get map by id (%u): %s", 487 id, strerror(errno)); 488 break; 489 } 490 491 err = bpf_obj_get_info_by_fd(fd, &info, &len); 492 if (err) { 493 p_err("can't get map info: %s", strerror(errno)); 494 close(fd); 495 break; 496 } 497 498 if (json_output) 499 show_map_close_json(fd, &info); 500 else 501 show_map_close_plain(fd, &info); 502 } 503 if (json_output) 504 jsonw_end_array(json_wtr); 505 506 return errno == ENOENT ? 0 : -1; 507 } 508 509 static int do_dump(int argc, char **argv) 510 { 511 void *key, *value, *prev_key; 512 unsigned int num_elems = 0; 513 struct bpf_map_info info = {}; 514 __u32 len = sizeof(info); 515 int err; 516 int fd; 517 518 if (argc != 2) 519 usage(); 520 521 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 522 if (fd < 0) 523 return -1; 524 525 if (map_is_map_of_maps(info.type) || map_is_map_of_progs(info.type)) { 526 p_err("Dumping maps of maps and program maps not supported"); 527 close(fd); 528 return -1; 529 } 530 531 key = malloc(info.key_size); 532 value = alloc_value(&info); 533 if (!key || !value) { 534 p_err("mem alloc failed"); 535 err = -1; 536 goto exit_free; 537 } 538 539 prev_key = NULL; 540 if (json_output) 541 jsonw_start_array(json_wtr); 542 while (true) { 543 err = bpf_map_get_next_key(fd, prev_key, key); 544 if (err) { 545 if (errno == ENOENT) 546 err = 0; 547 break; 548 } 549 550 if (!bpf_map_lookup_elem(fd, key, value)) { 551 if (json_output) 552 print_entry_json(&info, key, value); 553 else 554 print_entry_plain(&info, key, value); 555 } else { 556 if (json_output) { 557 jsonw_name(json_wtr, "key"); 558 print_hex_data_json(key, info.key_size); 559 jsonw_name(json_wtr, "value"); 560 jsonw_start_object(json_wtr); 561 jsonw_string_field(json_wtr, "error", 562 "can't lookup element"); 563 jsonw_end_object(json_wtr); 564 } else { 565 p_info("can't lookup element with key: "); 566 fprint_hex(stderr, key, info.key_size, " "); 567 fprintf(stderr, "\n"); 568 } 569 } 570 571 prev_key = key; 572 num_elems++; 573 } 574 575 if (json_output) 576 jsonw_end_array(json_wtr); 577 else 578 printf("Found %u element%s\n", num_elems, 579 num_elems != 1 ? "s" : ""); 580 581 exit_free: 582 free(key); 583 free(value); 584 close(fd); 585 586 return err; 587 } 588 589 static int do_update(int argc, char **argv) 590 { 591 struct bpf_map_info info = {}; 592 __u32 len = sizeof(info); 593 __u32 *value_fd = NULL; 594 __u32 flags = BPF_ANY; 595 void *key, *value; 596 int fd, err; 597 598 if (argc < 2) 599 usage(); 600 601 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 602 if (fd < 0) 603 return -1; 604 605 key = malloc(info.key_size); 606 value = alloc_value(&info); 607 if (!key || !value) { 608 p_err("mem alloc failed"); 609 err = -1; 610 goto exit_free; 611 } 612 613 err = parse_elem(argv, &info, key, value, info.key_size, 614 info.value_size, &flags, &value_fd); 615 if (err) 616 goto exit_free; 617 618 err = bpf_map_update_elem(fd, key, value, flags); 619 if (err) { 620 p_err("update failed: %s", strerror(errno)); 621 goto exit_free; 622 } 623 624 exit_free: 625 if (value_fd) 626 close(*value_fd); 627 free(key); 628 free(value); 629 close(fd); 630 631 if (!err && json_output) 632 jsonw_null(json_wtr); 633 return err; 634 } 635 636 static int do_lookup(int argc, char **argv) 637 { 638 struct bpf_map_info info = {}; 639 __u32 len = sizeof(info); 640 void *key, *value; 641 int err; 642 int fd; 643 644 if (argc < 2) 645 usage(); 646 647 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 648 if (fd < 0) 649 return -1; 650 651 key = malloc(info.key_size); 652 value = alloc_value(&info); 653 if (!key || !value) { 654 p_err("mem alloc failed"); 655 err = -1; 656 goto exit_free; 657 } 658 659 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL); 660 if (err) 661 goto exit_free; 662 663 err = bpf_map_lookup_elem(fd, key, value); 664 if (!err) { 665 if (json_output) 666 print_entry_json(&info, key, value); 667 else 668 print_entry_plain(&info, key, value); 669 } else if (errno == ENOENT) { 670 if (json_output) { 671 jsonw_null(json_wtr); 672 } else { 673 printf("key:\n"); 674 fprint_hex(stdout, key, info.key_size, " "); 675 printf("\n\nNot found\n"); 676 } 677 } else { 678 p_err("lookup failed: %s", strerror(errno)); 679 } 680 681 exit_free: 682 free(key); 683 free(value); 684 close(fd); 685 686 return err; 687 } 688 689 static int do_getnext(int argc, char **argv) 690 { 691 struct bpf_map_info info = {}; 692 __u32 len = sizeof(info); 693 void *key, *nextkey; 694 int err; 695 int fd; 696 697 if (argc < 2) 698 usage(); 699 700 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 701 if (fd < 0) 702 return -1; 703 704 key = malloc(info.key_size); 705 nextkey = malloc(info.key_size); 706 if (!key || !nextkey) { 707 p_err("mem alloc failed"); 708 err = -1; 709 goto exit_free; 710 } 711 712 if (argc) { 713 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, 714 NULL, NULL); 715 if (err) 716 goto exit_free; 717 } else { 718 free(key); 719 key = NULL; 720 } 721 722 err = bpf_map_get_next_key(fd, key, nextkey); 723 if (err) { 724 p_err("can't get next key: %s", strerror(errno)); 725 goto exit_free; 726 } 727 728 if (json_output) { 729 jsonw_start_object(json_wtr); 730 if (key) { 731 jsonw_name(json_wtr, "key"); 732 print_hex_data_json(key, info.key_size); 733 } else { 734 jsonw_null_field(json_wtr, "key"); 735 } 736 jsonw_name(json_wtr, "next_key"); 737 print_hex_data_json(nextkey, info.key_size); 738 jsonw_end_object(json_wtr); 739 } else { 740 if (key) { 741 printf("key:\n"); 742 fprint_hex(stdout, key, info.key_size, " "); 743 printf("\n"); 744 } else { 745 printf("key: None\n"); 746 } 747 printf("next key:\n"); 748 fprint_hex(stdout, nextkey, info.key_size, " "); 749 printf("\n"); 750 } 751 752 exit_free: 753 free(nextkey); 754 free(key); 755 close(fd); 756 757 return err; 758 } 759 760 static int do_delete(int argc, char **argv) 761 { 762 struct bpf_map_info info = {}; 763 __u32 len = sizeof(info); 764 void *key; 765 int err; 766 int fd; 767 768 if (argc < 2) 769 usage(); 770 771 fd = map_parse_fd_and_info(&argc, &argv, &info, &len); 772 if (fd < 0) 773 return -1; 774 775 key = malloc(info.key_size); 776 if (!key) { 777 p_err("mem alloc failed"); 778 err = -1; 779 goto exit_free; 780 } 781 782 err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL); 783 if (err) 784 goto exit_free; 785 786 err = bpf_map_delete_elem(fd, key); 787 if (err) 788 p_err("delete failed: %s", strerror(errno)); 789 790 exit_free: 791 free(key); 792 close(fd); 793 794 if (!err && json_output) 795 jsonw_null(json_wtr); 796 return err; 797 } 798 799 static int do_pin(int argc, char **argv) 800 { 801 int err; 802 803 err = do_pin_any(argc, argv, bpf_map_get_fd_by_id); 804 if (!err && json_output) 805 jsonw_null(json_wtr); 806 return err; 807 } 808 809 static int do_help(int argc, char **argv) 810 { 811 if (json_output) { 812 jsonw_null(json_wtr); 813 return 0; 814 } 815 816 fprintf(stderr, 817 "Usage: %s %s { show | list } [MAP]\n" 818 " %s %s dump MAP\n" 819 " %s %s update MAP key DATA value VALUE [UPDATE_FLAGS]\n" 820 " %s %s lookup MAP key DATA\n" 821 " %s %s getnext MAP [key DATA]\n" 822 " %s %s delete MAP key DATA\n" 823 " %s %s pin MAP FILE\n" 824 " %s %s event_pipe MAP [cpu N index M]\n" 825 " %s %s help\n" 826 "\n" 827 " " HELP_SPEC_MAP "\n" 828 " DATA := { [hex] BYTES }\n" 829 " " HELP_SPEC_PROGRAM "\n" 830 " VALUE := { DATA | MAP | PROG }\n" 831 " UPDATE_FLAGS := { any | exist | noexist }\n" 832 " " HELP_SPEC_OPTIONS "\n" 833 "", 834 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 835 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 836 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); 837 838 return 0; 839 } 840 841 static const struct cmd cmds[] = { 842 { "show", do_show }, 843 { "list", do_show }, 844 { "help", do_help }, 845 { "dump", do_dump }, 846 { "update", do_update }, 847 { "lookup", do_lookup }, 848 { "getnext", do_getnext }, 849 { "delete", do_delete }, 850 { "pin", do_pin }, 851 { "event_pipe", do_event_pipe }, 852 { 0 } 853 }; 854 855 int do_map(int argc, char **argv) 856 { 857 return cmd_select(cmds, argc, argv, do_help); 858 } 859