diff options
Diffstat (limited to 'tools/perf/util/bpf-loader.c')
-rw-r--r-- | tools/perf/util/bpf-loader.c | 724 |
1 files changed, 721 insertions, 3 deletions
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 540a7efa657e..0967ce601931 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c | |||
@@ -7,6 +7,7 @@ | |||
7 | 7 | ||
8 | #include <linux/bpf.h> | 8 | #include <linux/bpf.h> |
9 | #include <bpf/libbpf.h> | 9 | #include <bpf/libbpf.h> |
10 | #include <bpf/bpf.h> | ||
10 | #include <linux/err.h> | 11 | #include <linux/err.h> |
11 | #include <linux/string.h> | 12 | #include <linux/string.h> |
12 | #include "perf.h" | 13 | #include "perf.h" |
@@ -16,6 +17,7 @@ | |||
16 | #include "llvm-utils.h" | 17 | #include "llvm-utils.h" |
17 | #include "probe-event.h" | 18 | #include "probe-event.h" |
18 | #include "probe-finder.h" // for MAX_PROBES | 19 | #include "probe-finder.h" // for MAX_PROBES |
20 | #include "parse-events.h" | ||
19 | #include "llvm-utils.h" | 21 | #include "llvm-utils.h" |
20 | 22 | ||
21 | #define DEFINE_PRINT_FN(name, level) \ | 23 | #define DEFINE_PRINT_FN(name, level) \ |
@@ -108,8 +110,8 @@ void bpf__clear(void) | |||
108 | } | 110 | } |
109 | 111 | ||
110 | static void | 112 | static void |
111 | bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused, | 113 | clear_prog_priv(struct bpf_program *prog __maybe_unused, |
112 | void *_priv) | 114 | void *_priv) |
113 | { | 115 | { |
114 | struct bpf_prog_priv *priv = _priv; | 116 | struct bpf_prog_priv *priv = _priv; |
115 | 117 | ||
@@ -337,7 +339,7 @@ config_bpf_program(struct bpf_program *prog) | |||
337 | } | 339 | } |
338 | pr_debug("bpf: config '%s' is ok\n", config_str); | 340 | pr_debug("bpf: config '%s' is ok\n", config_str); |
339 | 341 | ||
340 | err = bpf_program__set_private(prog, priv, bpf_prog_priv__clear); | 342 | err = bpf_program__set_private(prog, priv, clear_prog_priv); |
341 | if (err) { | 343 | if (err) { |
342 | pr_debug("Failed to set priv for program '%s'\n", config_str); | 344 | pr_debug("Failed to set priv for program '%s'\n", config_str); |
343 | goto errout; | 345 | goto errout; |
@@ -739,6 +741,682 @@ int bpf__foreach_tev(struct bpf_object *obj, | |||
739 | return 0; | 741 | return 0; |
740 | } | 742 | } |
741 | 743 | ||
744 | enum bpf_map_op_type { | ||
745 | BPF_MAP_OP_SET_VALUE, | ||
746 | BPF_MAP_OP_SET_EVSEL, | ||
747 | }; | ||
748 | |||
749 | enum bpf_map_key_type { | ||
750 | BPF_MAP_KEY_ALL, | ||
751 | BPF_MAP_KEY_RANGES, | ||
752 | }; | ||
753 | |||
754 | struct bpf_map_op { | ||
755 | struct list_head list; | ||
756 | enum bpf_map_op_type op_type; | ||
757 | enum bpf_map_key_type key_type; | ||
758 | union { | ||
759 | struct parse_events_array array; | ||
760 | } k; | ||
761 | union { | ||
762 | u64 value; | ||
763 | struct perf_evsel *evsel; | ||
764 | } v; | ||
765 | }; | ||
766 | |||
767 | struct bpf_map_priv { | ||
768 | struct list_head ops_list; | ||
769 | }; | ||
770 | |||
771 | static void | ||
772 | bpf_map_op__delete(struct bpf_map_op *op) | ||
773 | { | ||
774 | if (!list_empty(&op->list)) | ||
775 | list_del(&op->list); | ||
776 | if (op->key_type == BPF_MAP_KEY_RANGES) | ||
777 | parse_events__clear_array(&op->k.array); | ||
778 | free(op); | ||
779 | } | ||
780 | |||
781 | static void | ||
782 | bpf_map_priv__purge(struct bpf_map_priv *priv) | ||
783 | { | ||
784 | struct bpf_map_op *pos, *n; | ||
785 | |||
786 | list_for_each_entry_safe(pos, n, &priv->ops_list, list) { | ||
787 | list_del_init(&pos->list); | ||
788 | bpf_map_op__delete(pos); | ||
789 | } | ||
790 | } | ||
791 | |||
792 | static void | ||
793 | bpf_map_priv__clear(struct bpf_map *map __maybe_unused, | ||
794 | void *_priv) | ||
795 | { | ||
796 | struct bpf_map_priv *priv = _priv; | ||
797 | |||
798 | bpf_map_priv__purge(priv); | ||
799 | free(priv); | ||
800 | } | ||
801 | |||
802 | static int | ||
803 | bpf_map_op_setkey(struct bpf_map_op *op, struct parse_events_term *term) | ||
804 | { | ||
805 | op->key_type = BPF_MAP_KEY_ALL; | ||
806 | if (!term) | ||
807 | return 0; | ||
808 | |||
809 | if (term->array.nr_ranges) { | ||
810 | size_t memsz = term->array.nr_ranges * | ||
811 | sizeof(op->k.array.ranges[0]); | ||
812 | |||
813 | op->k.array.ranges = memdup(term->array.ranges, memsz); | ||
814 | if (!op->k.array.ranges) { | ||
815 | pr_debug("No enough memory to alloc indices for map\n"); | ||
816 | return -ENOMEM; | ||
817 | } | ||
818 | op->key_type = BPF_MAP_KEY_RANGES; | ||
819 | op->k.array.nr_ranges = term->array.nr_ranges; | ||
820 | } | ||
821 | return 0; | ||
822 | } | ||
823 | |||
824 | static struct bpf_map_op * | ||
825 | bpf_map_op__new(struct parse_events_term *term) | ||
826 | { | ||
827 | struct bpf_map_op *op; | ||
828 | int err; | ||
829 | |||
830 | op = zalloc(sizeof(*op)); | ||
831 | if (!op) { | ||
832 | pr_debug("Failed to alloc bpf_map_op\n"); | ||
833 | return ERR_PTR(-ENOMEM); | ||
834 | } | ||
835 | INIT_LIST_HEAD(&op->list); | ||
836 | |||
837 | err = bpf_map_op_setkey(op, term); | ||
838 | if (err) { | ||
839 | free(op); | ||
840 | return ERR_PTR(err); | ||
841 | } | ||
842 | return op; | ||
843 | } | ||
844 | |||
845 | static int | ||
846 | bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op) | ||
847 | { | ||
848 | struct bpf_map_priv *priv; | ||
849 | const char *map_name; | ||
850 | int err; | ||
851 | |||
852 | map_name = bpf_map__get_name(map); | ||
853 | err = bpf_map__get_private(map, (void **)&priv); | ||
854 | if (err) { | ||
855 | pr_debug("Failed to get private from map %s\n", map_name); | ||
856 | return err; | ||
857 | } | ||
858 | |||
859 | if (!priv) { | ||
860 | priv = zalloc(sizeof(*priv)); | ||
861 | if (!priv) { | ||
862 | pr_debug("No enough memory to alloc map private\n"); | ||
863 | return -ENOMEM; | ||
864 | } | ||
865 | INIT_LIST_HEAD(&priv->ops_list); | ||
866 | |||
867 | if (bpf_map__set_private(map, priv, bpf_map_priv__clear)) { | ||
868 | free(priv); | ||
869 | return -BPF_LOADER_ERRNO__INTERNAL; | ||
870 | } | ||
871 | } | ||
872 | |||
873 | list_add_tail(&op->list, &priv->ops_list); | ||
874 | return 0; | ||
875 | } | ||
876 | |||
877 | static struct bpf_map_op * | ||
878 | bpf_map__add_newop(struct bpf_map *map, struct parse_events_term *term) | ||
879 | { | ||
880 | struct bpf_map_op *op; | ||
881 | int err; | ||
882 | |||
883 | op = bpf_map_op__new(term); | ||
884 | if (IS_ERR(op)) | ||
885 | return op; | ||
886 | |||
887 | err = bpf_map__add_op(map, op); | ||
888 | if (err) { | ||
889 | bpf_map_op__delete(op); | ||
890 | return ERR_PTR(err); | ||
891 | } | ||
892 | return op; | ||
893 | } | ||
894 | |||
895 | static int | ||
896 | __bpf_map__config_value(struct bpf_map *map, | ||
897 | struct parse_events_term *term) | ||
898 | { | ||
899 | struct bpf_map_def def; | ||
900 | struct bpf_map_op *op; | ||
901 | const char *map_name; | ||
902 | int err; | ||
903 | |||
904 | map_name = bpf_map__get_name(map); | ||
905 | |||
906 | err = bpf_map__get_def(map, &def); | ||
907 | if (err) { | ||
908 | pr_debug("Unable to get map definition from '%s'\n", | ||
909 | map_name); | ||
910 | return -BPF_LOADER_ERRNO__INTERNAL; | ||
911 | } | ||
912 | |||
913 | if (def.type != BPF_MAP_TYPE_ARRAY) { | ||
914 | pr_debug("Map %s type is not BPF_MAP_TYPE_ARRAY\n", | ||
915 | map_name); | ||
916 | return -BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE; | ||
917 | } | ||
918 | if (def.key_size < sizeof(unsigned int)) { | ||
919 | pr_debug("Map %s has incorrect key size\n", map_name); | ||
920 | return -BPF_LOADER_ERRNO__OBJCONF_MAP_KEYSIZE; | ||
921 | } | ||
922 | switch (def.value_size) { | ||
923 | case 1: | ||
924 | case 2: | ||
925 | case 4: | ||
926 | case 8: | ||
927 | break; | ||
928 | default: | ||
929 | pr_debug("Map %s has incorrect value size\n", map_name); | ||
930 | return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE; | ||
931 | } | ||
932 | |||
933 | op = bpf_map__add_newop(map, term); | ||
934 | if (IS_ERR(op)) | ||
935 | return PTR_ERR(op); | ||
936 | op->op_type = BPF_MAP_OP_SET_VALUE; | ||
937 | op->v.value = term->val.num; | ||
938 | return 0; | ||
939 | } | ||
940 | |||
941 | static int | ||
942 | bpf_map__config_value(struct bpf_map *map, | ||
943 | struct parse_events_term *term, | ||
944 | struct perf_evlist *evlist __maybe_unused) | ||
945 | { | ||
946 | if (!term->err_val) { | ||
947 | pr_debug("Config value not set\n"); | ||
948 | return -BPF_LOADER_ERRNO__OBJCONF_CONF; | ||
949 | } | ||
950 | |||
951 | if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM) { | ||
952 | pr_debug("ERROR: wrong value type for 'value'\n"); | ||
953 | return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE; | ||
954 | } | ||
955 | |||
956 | return __bpf_map__config_value(map, term); | ||
957 | } | ||
958 | |||
959 | static int | ||
960 | __bpf_map__config_event(struct bpf_map *map, | ||
961 | struct parse_events_term *term, | ||
962 | struct perf_evlist *evlist) | ||
963 | { | ||
964 | struct perf_evsel *evsel; | ||
965 | struct bpf_map_def def; | ||
966 | struct bpf_map_op *op; | ||
967 | const char *map_name; | ||
968 | int err; | ||
969 | |||
970 | map_name = bpf_map__get_name(map); | ||
971 | evsel = perf_evlist__find_evsel_by_str(evlist, term->val.str); | ||
972 | if (!evsel) { | ||
973 | pr_debug("Event (for '%s') '%s' doesn't exist\n", | ||
974 | map_name, term->val.str); | ||
975 | return -BPF_LOADER_ERRNO__OBJCONF_MAP_NOEVT; | ||
976 | } | ||
977 | |||
978 | err = bpf_map__get_def(map, &def); | ||
979 | if (err) { | ||
980 | pr_debug("Unable to get map definition from '%s'\n", | ||
981 | map_name); | ||
982 | return err; | ||
983 | } | ||
984 | |||
985 | /* | ||
986 | * No need to check key_size and value_size: | ||
987 | * kernel has already checked them. | ||
988 | */ | ||
989 | if (def.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) { | ||
990 | pr_debug("Map %s type is not BPF_MAP_TYPE_PERF_EVENT_ARRAY\n", | ||
991 | map_name); | ||
992 | return -BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE; | ||
993 | } | ||
994 | |||
995 | op = bpf_map__add_newop(map, term); | ||
996 | if (IS_ERR(op)) | ||
997 | return PTR_ERR(op); | ||
998 | op->op_type = BPF_MAP_OP_SET_EVSEL; | ||
999 | op->v.evsel = evsel; | ||
1000 | return 0; | ||
1001 | } | ||
1002 | |||
1003 | static int | ||
1004 | bpf_map__config_event(struct bpf_map *map, | ||
1005 | struct parse_events_term *term, | ||
1006 | struct perf_evlist *evlist) | ||
1007 | { | ||
1008 | if (!term->err_val) { | ||
1009 | pr_debug("Config value not set\n"); | ||
1010 | return -BPF_LOADER_ERRNO__OBJCONF_CONF; | ||
1011 | } | ||
1012 | |||
1013 | if (term->type_val != PARSE_EVENTS__TERM_TYPE_STR) { | ||
1014 | pr_debug("ERROR: wrong value type for 'event'\n"); | ||
1015 | return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE; | ||
1016 | } | ||
1017 | |||
1018 | return __bpf_map__config_event(map, term, evlist); | ||
1019 | } | ||
1020 | |||
1021 | struct bpf_obj_config__map_func { | ||
1022 | const char *config_opt; | ||
1023 | int (*config_func)(struct bpf_map *, struct parse_events_term *, | ||
1024 | struct perf_evlist *); | ||
1025 | }; | ||
1026 | |||
1027 | struct bpf_obj_config__map_func bpf_obj_config__map_funcs[] = { | ||
1028 | {"value", bpf_map__config_value}, | ||
1029 | {"event", bpf_map__config_event}, | ||
1030 | }; | ||
1031 | |||
1032 | static int | ||
1033 | config_map_indices_range_check(struct parse_events_term *term, | ||
1034 | struct bpf_map *map, | ||
1035 | const char *map_name) | ||
1036 | { | ||
1037 | struct parse_events_array *array = &term->array; | ||
1038 | struct bpf_map_def def; | ||
1039 | unsigned int i; | ||
1040 | int err; | ||
1041 | |||
1042 | if (!array->nr_ranges) | ||
1043 | return 0; | ||
1044 | if (!array->ranges) { | ||
1045 | pr_debug("ERROR: map %s: array->nr_ranges is %d but range array is NULL\n", | ||
1046 | map_name, (int)array->nr_ranges); | ||
1047 | return -BPF_LOADER_ERRNO__INTERNAL; | ||
1048 | } | ||
1049 | |||
1050 | err = bpf_map__get_def(map, &def); | ||
1051 | if (err) { | ||
1052 | pr_debug("ERROR: Unable to get map definition from '%s'\n", | ||
1053 | map_name); | ||
1054 | return -BPF_LOADER_ERRNO__INTERNAL; | ||
1055 | } | ||
1056 | |||
1057 | for (i = 0; i < array->nr_ranges; i++) { | ||
1058 | unsigned int start = array->ranges[i].start; | ||
1059 | size_t length = array->ranges[i].length; | ||
1060 | unsigned int idx = start + length - 1; | ||
1061 | |||
1062 | if (idx >= def.max_entries) { | ||
1063 | pr_debug("ERROR: index %d too large\n", idx); | ||
1064 | return -BPF_LOADER_ERRNO__OBJCONF_MAP_IDX2BIG; | ||
1065 | } | ||
1066 | } | ||
1067 | return 0; | ||
1068 | } | ||
1069 | |||
1070 | static int | ||
1071 | bpf__obj_config_map(struct bpf_object *obj, | ||
1072 | struct parse_events_term *term, | ||
1073 | struct perf_evlist *evlist, | ||
1074 | int *key_scan_pos) | ||
1075 | { | ||
1076 | /* key is "map:<mapname>.<config opt>" */ | ||
1077 | char *map_name = strdup(term->config + sizeof("map:") - 1); | ||
1078 | struct bpf_map *map; | ||
1079 | int err = -BPF_LOADER_ERRNO__OBJCONF_OPT; | ||
1080 | char *map_opt; | ||
1081 | size_t i; | ||
1082 | |||
1083 | if (!map_name) | ||
1084 | return -ENOMEM; | ||
1085 | |||
1086 | map_opt = strchr(map_name, '.'); | ||
1087 | if (!map_opt) { | ||
1088 | pr_debug("ERROR: Invalid map config: %s\n", map_name); | ||
1089 | goto out; | ||
1090 | } | ||
1091 | |||
1092 | *map_opt++ = '\0'; | ||
1093 | if (*map_opt == '\0') { | ||
1094 | pr_debug("ERROR: Invalid map option: %s\n", term->config); | ||
1095 | goto out; | ||
1096 | } | ||
1097 | |||
1098 | map = bpf_object__get_map_by_name(obj, map_name); | ||
1099 | if (!map) { | ||
1100 | pr_debug("ERROR: Map %s doesn't exist\n", map_name); | ||
1101 | err = -BPF_LOADER_ERRNO__OBJCONF_MAP_NOTEXIST; | ||
1102 | goto out; | ||
1103 | } | ||
1104 | |||
1105 | *key_scan_pos += strlen(map_opt); | ||
1106 | err = config_map_indices_range_check(term, map, map_name); | ||
1107 | if (err) | ||
1108 | goto out; | ||
1109 | *key_scan_pos -= strlen(map_opt); | ||
1110 | |||
1111 | for (i = 0; i < ARRAY_SIZE(bpf_obj_config__map_funcs); i++) { | ||
1112 | struct bpf_obj_config__map_func *func = | ||
1113 | &bpf_obj_config__map_funcs[i]; | ||
1114 | |||
1115 | if (strcmp(map_opt, func->config_opt) == 0) { | ||
1116 | err = func->config_func(map, term, evlist); | ||
1117 | goto out; | ||
1118 | } | ||
1119 | } | ||
1120 | |||
1121 | pr_debug("ERROR: Invalid map config option '%s'\n", map_opt); | ||
1122 | err = -BPF_LOADER_ERRNO__OBJCONF_MAP_OPT; | ||
1123 | out: | ||
1124 | free(map_name); | ||
1125 | if (!err) | ||
1126 | key_scan_pos += strlen(map_opt); | ||
1127 | return err; | ||
1128 | } | ||
1129 | |||
1130 | int bpf__config_obj(struct bpf_object *obj, | ||
1131 | struct parse_events_term *term, | ||
1132 | struct perf_evlist *evlist, | ||
1133 | int *error_pos) | ||
1134 | { | ||
1135 | int key_scan_pos = 0; | ||
1136 | int err; | ||
1137 | |||
1138 | if (!obj || !term || !term->config) | ||
1139 | return -EINVAL; | ||
1140 | |||
1141 | if (!prefixcmp(term->config, "map:")) { | ||
1142 | key_scan_pos = sizeof("map:") - 1; | ||
1143 | err = bpf__obj_config_map(obj, term, evlist, &key_scan_pos); | ||
1144 | goto out; | ||
1145 | } | ||
1146 | err = -BPF_LOADER_ERRNO__OBJCONF_OPT; | ||
1147 | out: | ||
1148 | if (error_pos) | ||
1149 | *error_pos = key_scan_pos; | ||
1150 | return err; | ||
1151 | |||
1152 | } | ||
1153 | |||
1154 | typedef int (*map_config_func_t)(const char *name, int map_fd, | ||
1155 | struct bpf_map_def *pdef, | ||
1156 | struct bpf_map_op *op, | ||
1157 | void *pkey, void *arg); | ||
1158 | |||
1159 | static int | ||
1160 | foreach_key_array_all(map_config_func_t func, | ||
1161 | void *arg, const char *name, | ||
1162 | int map_fd, struct bpf_map_def *pdef, | ||
1163 | struct bpf_map_op *op) | ||
1164 | { | ||
1165 | unsigned int i; | ||
1166 | int err; | ||
1167 | |||
1168 | for (i = 0; i < pdef->max_entries; i++) { | ||
1169 | err = func(name, map_fd, pdef, op, &i, arg); | ||
1170 | if (err) { | ||
1171 | pr_debug("ERROR: failed to insert value to %s[%u]\n", | ||
1172 | name, i); | ||
1173 | return err; | ||
1174 | } | ||
1175 | } | ||
1176 | return 0; | ||
1177 | } | ||
1178 | |||
1179 | static int | ||
1180 | foreach_key_array_ranges(map_config_func_t func, void *arg, | ||
1181 | const char *name, int map_fd, | ||
1182 | struct bpf_map_def *pdef, | ||
1183 | struct bpf_map_op *op) | ||
1184 | { | ||
1185 | unsigned int i, j; | ||
1186 | int err; | ||
1187 | |||
1188 | for (i = 0; i < op->k.array.nr_ranges; i++) { | ||
1189 | unsigned int start = op->k.array.ranges[i].start; | ||
1190 | size_t length = op->k.array.ranges[i].length; | ||
1191 | |||
1192 | for (j = 0; j < length; j++) { | ||
1193 | unsigned int idx = start + j; | ||
1194 | |||
1195 | err = func(name, map_fd, pdef, op, &idx, arg); | ||
1196 | if (err) { | ||
1197 | pr_debug("ERROR: failed to insert value to %s[%u]\n", | ||
1198 | name, idx); | ||
1199 | return err; | ||
1200 | } | ||
1201 | } | ||
1202 | } | ||
1203 | return 0; | ||
1204 | } | ||
1205 | |||
1206 | static int | ||
1207 | bpf_map_config_foreach_key(struct bpf_map *map, | ||
1208 | map_config_func_t func, | ||
1209 | void *arg) | ||
1210 | { | ||
1211 | int err, map_fd; | ||
1212 | const char *name; | ||
1213 | struct bpf_map_op *op; | ||
1214 | struct bpf_map_def def; | ||
1215 | struct bpf_map_priv *priv; | ||
1216 | |||
1217 | name = bpf_map__get_name(map); | ||
1218 | |||
1219 | err = bpf_map__get_private(map, (void **)&priv); | ||
1220 | if (err) { | ||
1221 | pr_debug("ERROR: failed to get private from map %s\n", name); | ||
1222 | return -BPF_LOADER_ERRNO__INTERNAL; | ||
1223 | } | ||
1224 | if (!priv || list_empty(&priv->ops_list)) { | ||
1225 | pr_debug("INFO: nothing to config for map %s\n", name); | ||
1226 | return 0; | ||
1227 | } | ||
1228 | |||
1229 | err = bpf_map__get_def(map, &def); | ||
1230 | if (err) { | ||
1231 | pr_debug("ERROR: failed to get definition from map %s\n", name); | ||
1232 | return -BPF_LOADER_ERRNO__INTERNAL; | ||
1233 | } | ||
1234 | map_fd = bpf_map__get_fd(map); | ||
1235 | if (map_fd < 0) { | ||
1236 | pr_debug("ERROR: failed to get fd from map %s\n", name); | ||
1237 | return map_fd; | ||
1238 | } | ||
1239 | |||
1240 | list_for_each_entry(op, &priv->ops_list, list) { | ||
1241 | switch (def.type) { | ||
1242 | case BPF_MAP_TYPE_ARRAY: | ||
1243 | case BPF_MAP_TYPE_PERF_EVENT_ARRAY: | ||
1244 | switch (op->key_type) { | ||
1245 | case BPF_MAP_KEY_ALL: | ||
1246 | err = foreach_key_array_all(func, arg, name, | ||
1247 | map_fd, &def, op); | ||
1248 | break; | ||
1249 | case BPF_MAP_KEY_RANGES: | ||
1250 | err = foreach_key_array_ranges(func, arg, name, | ||
1251 | map_fd, &def, | ||
1252 | op); | ||
1253 | break; | ||
1254 | default: | ||
1255 | pr_debug("ERROR: keytype for map '%s' invalid\n", | ||
1256 | name); | ||
1257 | return -BPF_LOADER_ERRNO__INTERNAL; | ||
1258 | } | ||
1259 | if (err) | ||
1260 | return err; | ||
1261 | break; | ||
1262 | default: | ||
1263 | pr_debug("ERROR: type of '%s' incorrect\n", name); | ||
1264 | return -BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE; | ||
1265 | } | ||
1266 | } | ||
1267 | |||
1268 | return 0; | ||
1269 | } | ||
1270 | |||
1271 | static int | ||
1272 | apply_config_value_for_key(int map_fd, void *pkey, | ||
1273 | size_t val_size, u64 val) | ||
1274 | { | ||
1275 | int err = 0; | ||
1276 | |||
1277 | switch (val_size) { | ||
1278 | case 1: { | ||
1279 | u8 _val = (u8)(val); | ||
1280 | err = bpf_map_update_elem(map_fd, pkey, &_val, BPF_ANY); | ||
1281 | break; | ||
1282 | } | ||
1283 | case 2: { | ||
1284 | u16 _val = (u16)(val); | ||
1285 | err = bpf_map_update_elem(map_fd, pkey, &_val, BPF_ANY); | ||
1286 | break; | ||
1287 | } | ||
1288 | case 4: { | ||
1289 | u32 _val = (u32)(val); | ||
1290 | err = bpf_map_update_elem(map_fd, pkey, &_val, BPF_ANY); | ||
1291 | break; | ||
1292 | } | ||
1293 | case 8: { | ||
1294 | err = bpf_map_update_elem(map_fd, pkey, &val, BPF_ANY); | ||
1295 | break; | ||
1296 | } | ||
1297 | default: | ||
1298 | pr_debug("ERROR: invalid value size\n"); | ||
1299 | return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE; | ||
1300 | } | ||
1301 | if (err && errno) | ||
1302 | err = -errno; | ||
1303 | return err; | ||
1304 | } | ||
1305 | |||
1306 | static int | ||
1307 | apply_config_evsel_for_key(const char *name, int map_fd, void *pkey, | ||
1308 | struct perf_evsel *evsel) | ||
1309 | { | ||
1310 | struct xyarray *xy = evsel->fd; | ||
1311 | struct perf_event_attr *attr; | ||
1312 | unsigned int key, events; | ||
1313 | bool check_pass = false; | ||
1314 | int *evt_fd; | ||
1315 | int err; | ||
1316 | |||
1317 | if (!xy) { | ||
1318 | pr_debug("ERROR: evsel not ready for map %s\n", name); | ||
1319 | return -BPF_LOADER_ERRNO__INTERNAL; | ||
1320 | } | ||
1321 | |||
1322 | if (xy->row_size / xy->entry_size != 1) { | ||
1323 | pr_debug("ERROR: Dimension of target event is incorrect for map %s\n", | ||
1324 | name); | ||
1325 | return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM; | ||
1326 | } | ||
1327 | |||
1328 | attr = &evsel->attr; | ||
1329 | if (attr->inherit) { | ||
1330 | pr_debug("ERROR: Can't put inherit event into map %s\n", name); | ||
1331 | return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH; | ||
1332 | } | ||
1333 | |||
1334 | if (perf_evsel__is_bpf_output(evsel)) | ||
1335 | check_pass = true; | ||
1336 | if (attr->type == PERF_TYPE_RAW) | ||
1337 | check_pass = true; | ||
1338 | if (attr->type == PERF_TYPE_HARDWARE) | ||
1339 | check_pass = true; | ||
1340 | if (!check_pass) { | ||
1341 | pr_debug("ERROR: Event type is wrong for map %s\n", name); | ||
1342 | return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE; | ||
1343 | } | ||
1344 | |||
1345 | events = xy->entries / (xy->row_size / xy->entry_size); | ||
1346 | key = *((unsigned int *)pkey); | ||
1347 | if (key >= events) { | ||
1348 | pr_debug("ERROR: there is no event %d for map %s\n", | ||
1349 | key, name); | ||
1350 | return -BPF_LOADER_ERRNO__OBJCONF_MAP_MAPSIZE; | ||
1351 | } | ||
1352 | evt_fd = xyarray__entry(xy, key, 0); | ||
1353 | err = bpf_map_update_elem(map_fd, pkey, evt_fd, BPF_ANY); | ||
1354 | if (err && errno) | ||
1355 | err = -errno; | ||
1356 | return err; | ||
1357 | } | ||
1358 | |||
1359 | static int | ||
1360 | apply_obj_config_map_for_key(const char *name, int map_fd, | ||
1361 | struct bpf_map_def *pdef __maybe_unused, | ||
1362 | struct bpf_map_op *op, | ||
1363 | void *pkey, void *arg __maybe_unused) | ||
1364 | { | ||
1365 | int err; | ||
1366 | |||
1367 | switch (op->op_type) { | ||
1368 | case BPF_MAP_OP_SET_VALUE: | ||
1369 | err = apply_config_value_for_key(map_fd, pkey, | ||
1370 | pdef->value_size, | ||
1371 | op->v.value); | ||
1372 | break; | ||
1373 | case BPF_MAP_OP_SET_EVSEL: | ||
1374 | err = apply_config_evsel_for_key(name, map_fd, pkey, | ||
1375 | op->v.evsel); | ||
1376 | break; | ||
1377 | default: | ||
1378 | pr_debug("ERROR: unknown value type for '%s'\n", name); | ||
1379 | err = -BPF_LOADER_ERRNO__INTERNAL; | ||
1380 | } | ||
1381 | return err; | ||
1382 | } | ||
1383 | |||
1384 | static int | ||
1385 | apply_obj_config_map(struct bpf_map *map) | ||
1386 | { | ||
1387 | return bpf_map_config_foreach_key(map, | ||
1388 | apply_obj_config_map_for_key, | ||
1389 | NULL); | ||
1390 | } | ||
1391 | |||
1392 | static int | ||
1393 | apply_obj_config_object(struct bpf_object *obj) | ||
1394 | { | ||
1395 | struct bpf_map *map; | ||
1396 | int err; | ||
1397 | |||
1398 | bpf_map__for_each(map, obj) { | ||
1399 | err = apply_obj_config_map(map); | ||
1400 | if (err) | ||
1401 | return err; | ||
1402 | } | ||
1403 | return 0; | ||
1404 | } | ||
1405 | |||
1406 | int bpf__apply_obj_config(void) | ||
1407 | { | ||
1408 | struct bpf_object *obj, *tmp; | ||
1409 | int err; | ||
1410 | |||
1411 | bpf_object__for_each_safe(obj, tmp) { | ||
1412 | err = apply_obj_config_object(obj); | ||
1413 | if (err) | ||
1414 | return err; | ||
1415 | } | ||
1416 | |||
1417 | return 0; | ||
1418 | } | ||
1419 | |||
742 | #define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) | 1420 | #define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) |
743 | #define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c) | 1421 | #define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c) |
744 | #define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START) | 1422 | #define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START) |
@@ -753,6 +1431,20 @@ static const char *bpf_loader_strerror_table[NR_ERRNO] = { | |||
753 | [ERRCODE_OFFSET(PROLOGUE)] = "Failed to generate prologue", | 1431 | [ERRCODE_OFFSET(PROLOGUE)] = "Failed to generate prologue", |
754 | [ERRCODE_OFFSET(PROLOGUE2BIG)] = "Prologue too big for program", | 1432 | [ERRCODE_OFFSET(PROLOGUE2BIG)] = "Prologue too big for program", |
755 | [ERRCODE_OFFSET(PROLOGUEOOB)] = "Offset out of bound for prologue", | 1433 | [ERRCODE_OFFSET(PROLOGUEOOB)] = "Offset out of bound for prologue", |
1434 | [ERRCODE_OFFSET(OBJCONF_OPT)] = "Invalid object config option", | ||
1435 | [ERRCODE_OFFSET(OBJCONF_CONF)] = "Config value not set (missing '=')", | ||
1436 | [ERRCODE_OFFSET(OBJCONF_MAP_OPT)] = "Invalid object map config option", | ||
1437 | [ERRCODE_OFFSET(OBJCONF_MAP_NOTEXIST)] = "Target map doesn't exist", | ||
1438 | [ERRCODE_OFFSET(OBJCONF_MAP_VALUE)] = "Incorrect value type for map", | ||
1439 | [ERRCODE_OFFSET(OBJCONF_MAP_TYPE)] = "Incorrect map type", | ||
1440 | [ERRCODE_OFFSET(OBJCONF_MAP_KEYSIZE)] = "Incorrect map key size", | ||
1441 | [ERRCODE_OFFSET(OBJCONF_MAP_VALUESIZE)] = "Incorrect map value size", | ||
1442 | [ERRCODE_OFFSET(OBJCONF_MAP_NOEVT)] = "Event not found for map setting", | ||
1443 | [ERRCODE_OFFSET(OBJCONF_MAP_MAPSIZE)] = "Invalid map size for event setting", | ||
1444 | [ERRCODE_OFFSET(OBJCONF_MAP_EVTDIM)] = "Event dimension too large", | ||
1445 | [ERRCODE_OFFSET(OBJCONF_MAP_EVTINH)] = "Doesn't support inherit event", | ||
1446 | [ERRCODE_OFFSET(OBJCONF_MAP_EVTTYPE)] = "Wrong event type for map", | ||
1447 | [ERRCODE_OFFSET(OBJCONF_MAP_IDX2BIG)] = "Index too large", | ||
756 | }; | 1448 | }; |
757 | 1449 | ||
758 | static int | 1450 | static int |
@@ -872,3 +1564,29 @@ int bpf__strerror_load(struct bpf_object *obj, | |||
872 | bpf__strerror_end(buf, size); | 1564 | bpf__strerror_end(buf, size); |
873 | return 0; | 1565 | return 0; |
874 | } | 1566 | } |
1567 | |||
1568 | int bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused, | ||
1569 | struct parse_events_term *term __maybe_unused, | ||
1570 | struct perf_evlist *evlist __maybe_unused, | ||
1571 | int *error_pos __maybe_unused, int err, | ||
1572 | char *buf, size_t size) | ||
1573 | { | ||
1574 | bpf__strerror_head(err, buf, size); | ||
1575 | bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE, | ||
1576 | "Can't use this config term with this map type"); | ||
1577 | bpf__strerror_end(buf, size); | ||
1578 | return 0; | ||
1579 | } | ||
1580 | |||
1581 | int bpf__strerror_apply_obj_config(int err, char *buf, size_t size) | ||
1582 | { | ||
1583 | bpf__strerror_head(err, buf, size); | ||
1584 | bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM, | ||
1585 | "Cannot set event to BPF map in multi-thread tracing"); | ||
1586 | bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH, | ||
1587 | "%s (Hint: use -i to turn off inherit)", emsg); | ||
1588 | bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE, | ||
1589 | "Can only put raw, hardware and BPF output event into a BPF map"); | ||
1590 | bpf__strerror_end(buf, size); | ||
1591 | return 0; | ||
1592 | } | ||