| @@ -332,6 +332,23 @@ static int parse_trace_event_arg(char *arg, struct fetch_insn *code, · 331 unmodified lines |
| 332 | 332 | return -ENOENT; |
| 333 | 333 | } |
| 334 | 334 | |
| 335 | +static int parse_trace_event(char *arg, struct fetch_insn *code, |
| 336 | + struct traceprobe_parse_context *ctx) |
| 337 | +{ |
| 338 | + int ret; |
| 339 | + |
| 340 | + if (code->data) |
| 341 | + return -EFAULT; |
| 342 | + ret = parse_trace_event_arg(arg, code, ctx); |
| 343 | + if (!ret) |
| 344 | + return 0; |
| 345 | + if (strcmp(arg, "comm") == 0 || strcmp(arg, "COMM") == 0) { |
| 346 | + code->op = FETCH_OP_COMM; |
| 347 | + return 0; |
| 348 | + } |
| 349 | + return -EINVAL; |
| 350 | +} |
| 351 | + |
| 335 | 352 | #ifdef CONFIG_PROBE_EVENTS_BTF_ARGS |
| 336 | 353 | |
| 337 | 354 | static u32 btf_type_int(const struct btf_type *t) |
| @@ -376,11 +393,16 @@ static bool btf_type_is_char_array(struct btf *btf, const struct btf_type *type) · 38 unmodified lines |
| 376 | 393 | && BTF_INT_BITS(intdata) == 8; |
| 377 | 394 | } |
| 378 | 395 | |
| 396 | +static struct btf *ctx_btf(struct traceprobe_parse_context *ctx) |
| 397 | +{ |
| 398 | + return ctx->struct_btf ? : ctx->btf; |
| 399 | +} |
| 400 | + |
| 379 | 401 | static int check_prepare_btf_string_fetch(char *typename, |
| 380 | 402 | struct fetch_insn **pcode, |
| 381 | 403 | struct traceprobe_parse_context *ctx) |
| 382 | 404 | { |
| 383 | | − struct btf *btf = ctx->btf; |
| 405 | + struct btf *btf = ctx_btf(ctx); |
| 384 | 406 | |
| 385 | 407 | if (!btf || !ctx->last_type) |
| 386 | 408 | return 0; |
| @@ -506,6 +528,15 @@ static int query_btf_context(struct traceprobe_parse_context *ctx) · 119 unmodified lines |
| 506 | 528 | return 0; |
| 507 | 529 | } |
| 508 | 530 | |
| 531 | +static void clear_struct_btf(struct traceprobe_parse_context *ctx) |
| 532 | +{ |
| 533 | + if (ctx->struct_btf) { |
| 534 | + btf_put(ctx->struct_btf); |
| 535 | + ctx->struct_btf = NULL; |
| 536 | + ctx->last_struct = NULL; |
| 537 | + } |
| 538 | +} |
| 539 | + |
| 509 | 540 | static void clear_btf_context(struct traceprobe_parse_context *ctx) |
| 510 | 541 | { |
| 511 | 542 | if (ctx->btf) { |
| @@ -554,22 +585,29 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type, · 42 unmodified lines |
| 554 | 585 | struct fetch_insn *code = *pcode; |
| 555 | 586 | const struct btf_member *field; |
| 556 | 587 | u32 bitoffs, anon_offs; |
| 588 | + bool is_struct = ctx->struct_btf != NULL; |
| 589 | + struct btf *btf = ctx_btf(ctx); |
| 557 | 590 | char *next; |
| 558 | 591 | int is_ptr; |
| 559 | 592 | s32 tid; |
| 560 | 593 | |
| 561 | 594 | do { |
| 562 | | − /* Outer loop for solving arrow operator ('->') */ |
| 563 | | − if (BTF_INFO_KIND(type->info) != BTF_KIND_PTR) { |
| 564 | | − trace_probe_log_err(ctx->offset, NO_PTR_STRCT); |
| 565 | | − return -EINVAL; |
| 566 | | − } |
| 567 | | − /* Convert a struct pointer type to a struct type */ |
| 568 | | − type = btf_type_skip_modifiers(ctx->btf, type->type, &tid); |
| 569 | | − if (!type) { |
| 570 | | − trace_probe_log_err(ctx->offset, BAD_BTF_TID); |
| 571 | | − return -EINVAL; |
| 595 | + if (!is_struct) { |
| 596 | + /* Outer loop for solving arrow operator ('->') */ |
| 597 | + if (BTF_INFO_KIND(type->info) != BTF_KIND_PTR) { |
| 598 | + trace_probe_log_err(ctx->offset, NO_PTR_STRCT); |
| 599 | + return -EINVAL; |
| 600 | + } |
| 601 | + |
| 602 | + /* Convert a struct pointer type to a struct type */ |
| 603 | + type = btf_type_skip_modifiers(btf, type->type, &tid); |
| 604 | + if (!type) { |
| 605 | + trace_probe_log_err(ctx->offset, BAD_BTF_TID); |
| 606 | + return -EINVAL; |
| 607 | + } |
| 572 | 608 | } |
| 609 | + /* Only the first type can skip being a pointer */ |
| 610 | + is_struct = false; |
| 573 | 611 | |
| 574 | 612 | bitoffs = 0; |
| 575 | 613 | do { |
| @@ -580,7 +618,7 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type, · 4 unmodified lines |
| 580 | 618 | return is_ptr; |
| 581 | 619 | |
| 582 | 620 | anon_offs = 0; |
| 583 | | − field = btf_find_struct_member(ctx->btf, type, fieldname, |
| 621 | + field = btf_find_struct_member(btf, type, fieldname, |
| 584 | 622 | &anon_offs); |
| 585 | 623 | if (IS_ERR(field)) { |
| 586 | 624 | trace_probe_log_err(ctx->offset, BAD_BTF_TID); |
| @@ -602,7 +640,7 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type, · 15 unmodified lines |
| 602 | 640 | ctx->last_bitsize = 0; |
| 603 | 641 | } |
| 604 | 642 | |
| 605 | | − type = btf_type_skip_modifiers(ctx->btf, field->type, &tid); |
| 643 | + type = btf_type_skip_modifiers(btf, field->type, &tid); |
| 606 | 644 | if (!type) { |
| 607 | 645 | trace_probe_log_err(ctx->offset, BAD_BTF_TID); |
| 608 | 646 | return -EINVAL; |
| @@ -640,7 +678,7 @@ static int parse_btf_arg(char *varname, · 31 unmodified lines |
| 640 | 678 | int i, is_ptr, ret; |
| 641 | 679 | u32 tid; |
| 642 | 680 | |
| 643 | | − if (WARN_ON_ONCE(!ctx->funcname)) |
| 681 | + if (WARN_ON_ONCE(!ctx->funcname && !(ctx->flags & TPARG_FL_TEVENT))) |
| 644 | 682 | return -EINVAL; |
| 645 | 683 | |
| 646 | 684 | is_ptr = split_next_field(varname, &field, ctx); |
| @@ -653,6 +691,19 @@ static int parse_btf_arg(char *varname, · 6 unmodified lines |
| 653 | 691 | return -EOPNOTSUPP; |
| 654 | 692 | } |
| 655 | 693 | |
| 694 | + if (ctx->flags & TPARG_FL_TEVENT) { |
| 695 | + ret = parse_trace_event(varname, code, ctx); |
| 696 | + if (ret < 0) { |
| 697 | + trace_probe_log_err(ctx->offset, BAD_ATTACH_ARG); |
| 698 | + return ret; |
| 699 | + } |
| 700 | + /* TEVENT is only here via a typecast */ |
| 701 | + if (WARN_ON_ONCE(ctx->struct_btf == NULL)) |
| 702 | + return -EINVAL; |
| 703 | + type = ctx->last_struct; |
| 704 | + goto found_type; |
| 705 | + } |
| 706 | + |
| 656 | 707 | if (ctx->flags & TPARG_FL_RETURN && !strcmp(varname, "$retval")) { |
| 657 | 708 | code->op = FETCH_OP_RETVAL; |
| 658 | 709 | /* Check whether the function return type is not void */ |
| @@ -709,6 +760,7 @@ static int parse_btf_arg(char *varname, · 50 unmodified lines |
| 709 | 760 | |
| 710 | 761 | found: |
| 711 | 762 | type = btf_type_skip_modifiers(ctx->btf, tid, &tid); |
| 763 | +found_type: |
| 712 | 764 | if (!type) { |
| 713 | 765 | trace_probe_log_err(ctx->offset, BAD_BTF_TID); |
| 714 | 766 | return -EINVAL; |
| @@ -727,7 +779,7 @@ found: · 12 unmodified lines |
| 727 | 779 | static const struct fetch_type *find_fetch_type_from_btf_type( |
| 728 | 780 | struct traceprobe_parse_context *ctx) |
| 729 | 781 | { |
| 730 | | − struct btf *btf = ctx->btf; |
| 782 | + struct btf *btf = ctx_btf(ctx); |
| 731 | 783 | const char *typestr = NULL; |
| 732 | 784 | |
| 733 | 785 | if (btf && ctx->last_type) |
| @@ -758,7 +810,67 @@ static int parse_btf_bitfield(struct fetch_insn **pcode, · 24 unmodified lines |
| 758 | 810 | return 0; |
| 759 | 811 | } |
| 760 | 812 | |
| 761 | | −#else |
| 813 | +static int query_btf_struct(const char *sname, struct traceprobe_parse_context *ctx) |
| 814 | +{ |
| 815 | + struct btf *btf = NULL; |
| 816 | + int id; |
| 817 | + |
| 818 | + /* A struct_btf should only be used by a single argument */ |
| 819 | + if (WARN_ON_ONCE(ctx->struct_btf)) { |
| 820 | + btf_put(ctx->struct_btf); |
| 821 | + ctx->struct_btf = NULL; |
| 822 | + } |
| 823 | + |
| 824 | + id = bpf_find_btf_id(sname, BTF_KIND_STRUCT, &btf); |
| 825 | + if (id < 0) |
| 826 | + return id; |
| 827 | + ctx->struct_btf = btf; |
| 828 | + ctx->last_struct = btf_type_by_id(ctx->struct_btf, id); |
| 829 | + return 0; |
| 830 | +} |
| 831 | + |
| 832 | +static int handle_typecast(char *arg, struct fetch_insn **pcode, |
| 833 | + struct fetch_insn *end, |
| 834 | + struct traceprobe_parse_context *ctx) |
| 835 | +{ |
| 836 | + char *tmp; |
| 837 | + int ret; |
| 838 | + |
| 839 | + /* Currently this only works for eprobes */ |
| 840 | + if (!(ctx->flags & TPARG_FL_TEVENT)) { |
| 841 | + trace_probe_log_err(ctx->offset, TYPECAST_NOT_EVENT); |
| 842 | + return -EINVAL; |
| 843 | + } |
| 844 | + |
| 845 | + tmp = strchr(arg, ')'); |
| 846 | + if (!tmp) { |
| 847 | + trace_probe_log_err(ctx->offset + strlen(arg), |
| 848 | + DEREF_OPEN_BRACE); |
| 849 | + return -EINVAL; |
| 850 | + } |
| 851 | + *tmp = '\0'; |
| 852 | + ret = query_btf_struct(arg + 1, ctx); |
| 853 | + *tmp = ')'; |
| 854 | + |
| 855 | + if (ret < 0) { |
| 856 | + trace_probe_log_err(ctx->offset + 1, NO_PTR_STRCT); |
| 857 | + return -EINVAL; |
| 858 | + } |
| 859 | + |
| 860 | + tmp++; |
| 861 | + |
| 862 | + ctx->offset += tmp - arg; |
| 863 | + ret = parse_btf_arg(tmp, pcode, end, ctx); |
| 864 | + return ret; |
| 865 | +} |
| 866 | + |
| 867 | +#else /* !CONFIG_PROBE_EVENTS_BTF_ARGS */ |
| 868 | + |
| 869 | +static void clear_struct_btf(struct traceprobe_parse_context *ctx) |
| 870 | +{ |
| 871 | + ctx->struct_btf = NULL; |
| 872 | +} |
| 873 | + |
| 762 | 874 | static void clear_btf_context(struct traceprobe_parse_context *ctx) |
| 763 | 875 | { |
| 764 | 876 | ctx->btf = NULL; |
| @@ -794,7 +906,15 @@ static int check_prepare_btf_string_fetch(char *typename, · 29 unmodified lines |
| 794 | 906 | return 0; |
| 795 | 907 | } |
| 796 | 908 | |
| 797 | | −#endif |
| 909 | +static int handle_typecast(char *arg, struct fetch_insn **pcode, |
| 910 | + struct fetch_insn *end, |
| 911 | + struct traceprobe_parse_context *ctx) |
| 912 | +{ |
| 913 | + trace_probe_log_err(ctx->offset, NOSUP_BTFARG); |
| 914 | + return -EOPNOTSUPP; |
| 915 | +} |
| 916 | + |
| 917 | +#endif /* CONFIG_PROBE_EVENTS_BTF_ARGS */ |
| 798 | 918 | |
| 799 | 919 | #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API |
| 800 | 920 | |
| @@ -838,15 +958,10 @@ static int __store_entry_arg(struct trace_probe *tp, int argnum) · 37 unmodified lines |
| 838 | 958 | int i, offset, last_offset = 0; |
| 839 | 959 | |
| 840 | 960 | if (!earg) { |
| 841 | | − earg = kzalloc_obj(*tp->entry_arg); |
| 961 | + earg = kzalloc_flex(*earg, code, 2 * tp->nr_args + 1); |
| 842 | 962 | if (!earg) |
| 843 | 963 | return -ENOMEM; |
| 844 | 964 | earg->size = 2 * tp->nr_args + 1; |
| 845 | | − earg->code = kzalloc_objs(struct fetch_insn, earg->size); |
| 846 | | − if (!earg->code) { |
| 847 | | − kfree(earg); |
| 848 | | − return -ENOMEM; |
| 849 | | − } |
| 850 | 965 | /* Fill the code buffer with 'end' to simplify it */ |
| 851 | 966 | for (i = 0; i < earg->size; i++) |
| 852 | 967 | earg->code[i].op = FETCH_OP_END; |
| @@ -953,16 +1068,9 @@ static int parse_probe_vars(char *orig_arg, const struct fetch_type *t, · 100 unmodified lines |
| 953 | 1068 | int len; |
| 954 | 1069 | |
| 955 | 1070 | if (ctx->flags & TPARG_FL_TEVENT) { |
| 956 | | − if (code->data) |
| 957 | | − return -EFAULT; |
| 958 | | − ret = parse_trace_event_arg(arg, code, ctx); |
| 959 | | − if (!ret) |
| 960 | | − return 0; |
| 961 | | − if (strcmp(arg, "comm") == 0 || strcmp(arg, "COMM") == 0) { |
| 962 | | − code->op = FETCH_OP_COMM; |
| 963 | | − return 0; |
| 964 | | − } |
| 965 | | − goto inval; |
| 1071 | + if (parse_trace_event(arg, code, ctx) < 0) |
| 1072 | + goto inval; |
| 1073 | + return 0; |
| 966 | 1074 | } |
| 967 | 1075 | |
| 968 | 1076 | if (str_has_prefix(arg, "retval")) { |
| @@ -1229,6 +1337,9 @@ parse_probe_arg(char *arg, const struct fetch_type *type, · 260 unmodified lines |
| 1229 | 1337 | code->op = FETCH_OP_IMM; |
| 1230 | 1338 | } |
| 1231 | 1339 | break; |
| 1340 | + case '(': |
| 1341 | + ret = handle_typecast(arg, pcode, end, ctx); |
| 1342 | + break; |
| 1232 | 1343 | default: |
| 1233 | 1344 | if (isalpha(arg[0]) || arg[0] == '_') { /* BTF variable */ |
| 1234 | 1345 | if (!tparg_is_function_entry(ctx->flags) && |
| @@ -1561,6 +1672,9 @@ fail: · 326 unmodified lines |
| 1561 | 1672 | } |
| 1562 | 1673 | kfree(tmp); |
| 1563 | 1674 | |
| 1675 | + /* struct_btf should not be passed to other arguments */ |
| 1676 | + clear_struct_btf(ctx); |
| 1677 | + |
| 1564 | 1678 | return ret; |
| 1565 | 1679 | } |
| 1566 | 1680 | |
| @@ -2049,7 +2163,6 @@ void trace_probe_cleanup(struct trace_probe *tp) · 482 unmodified lines |
| 2049 | 2163 | traceprobe_free_probe_arg(&tp->args[i]); |
| 2050 | 2164 | |
| 2051 | 2165 | if (tp->entry_arg) { |
| 2052 | | − kfree(tp->entry_arg->code); |
| 2053 | 2166 | kfree(tp->entry_arg); |
| 2054 | 2167 | tp->entry_arg = NULL; |
| 2055 | 2168 | } |