diff options
| author | Song Liu <songliubraving@fb.com> | 2019-03-12 01:30:38 -0400 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2019-03-19 15:52:06 -0400 |
| commit | 34be16466d4dc06f3d604dafbcdb3327b72e78da (patch) | |
| tree | ac000724283e4cf8052a9604b71c8f6885d53c2e | |
| parent | 71184c6ab7e60fd59d8dbc8fed62a1c753dc4934 (diff) | |
tools lib bpf: Introduce bpf_program__get_prog_info_linear()
Currently, bpf_prog_info includes 9 arrays. The user has the option to
fetch any combination of these arrays. However, this requires a lot of
handling.
This work becomes more tricky when we need to store bpf_prog_info to a
file, because these arrays are allocated independently.
This patch introduces 'struct bpf_prog_info_linear', which stores arrays
of bpf_prog_info in continuous memory.
Helper functions are introduced to unify the work to get different sets
of bpf_prog_info. Specifically, bpf_program__get_prog_info_linear()
allows the user to select which arrays to fetch, and handles details for
the user.
Please see the comments right before 'enum bpf_prog_info_array' for more
details and examples.
Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lkml.kernel.org/r/ce92c091-e80d-a0c1-4aa0-987706c42b20@iogearbox.net
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: kernel-team@fb.com
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <sdf@google.com>
Link: http://lkml.kernel.org/r/20190312053051.2690567-3-songliubraving@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
| -rw-r--r-- | tools/lib/bpf/libbpf.c | 251 | ||||
| -rw-r--r-- | tools/lib/bpf/libbpf.h | 63 | ||||
| -rw-r--r-- | tools/lib/bpf/libbpf.map | 3 |
3 files changed, 317 insertions, 0 deletions
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 4884557aa17f..8fb6e89b4b2c 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c | |||
| @@ -112,6 +112,11 @@ void libbpf_print(enum libbpf_print_level level, const char *format, ...) | |||
| 112 | # define LIBBPF_ELF_C_READ_MMAP ELF_C_READ | 112 | # define LIBBPF_ELF_C_READ_MMAP ELF_C_READ |
| 113 | #endif | 113 | #endif |
| 114 | 114 | ||
| 115 | static inline __u64 ptr_to_u64(const void *ptr) | ||
| 116 | { | ||
| 117 | return (__u64) (unsigned long) ptr; | ||
| 118 | } | ||
| 119 | |||
| 115 | struct bpf_capabilities { | 120 | struct bpf_capabilities { |
| 116 | /* v4.14: kernel support for program & map names. */ | 121 | /* v4.14: kernel support for program & map names. */ |
| 117 | __u32 name:1; | 122 | __u32 name:1; |
| @@ -2997,3 +3002,249 @@ bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size, | |||
| 2997 | ring_buffer_write_tail(header, data_tail); | 3002 | ring_buffer_write_tail(header, data_tail); |
| 2998 | return ret; | 3003 | return ret; |
| 2999 | } | 3004 | } |
| 3005 | |||
| 3006 | struct bpf_prog_info_array_desc { | ||
| 3007 | int array_offset; /* e.g. offset of jited_prog_insns */ | ||
| 3008 | int count_offset; /* e.g. offset of jited_prog_len */ | ||
| 3009 | int size_offset; /* > 0: offset of rec size, | ||
| 3010 | * < 0: fix size of -size_offset | ||
| 3011 | */ | ||
| 3012 | }; | ||
| 3013 | |||
| 3014 | static struct bpf_prog_info_array_desc bpf_prog_info_array_desc[] = { | ||
| 3015 | [BPF_PROG_INFO_JITED_INSNS] = { | ||
| 3016 | offsetof(struct bpf_prog_info, jited_prog_insns), | ||
| 3017 | offsetof(struct bpf_prog_info, jited_prog_len), | ||
| 3018 | -1, | ||
| 3019 | }, | ||
| 3020 | [BPF_PROG_INFO_XLATED_INSNS] = { | ||
| 3021 | offsetof(struct bpf_prog_info, xlated_prog_insns), | ||
| 3022 | offsetof(struct bpf_prog_info, xlated_prog_len), | ||
| 3023 | -1, | ||
| 3024 | }, | ||
| 3025 | [BPF_PROG_INFO_MAP_IDS] = { | ||
| 3026 | offsetof(struct bpf_prog_info, map_ids), | ||
| 3027 | offsetof(struct bpf_prog_info, nr_map_ids), | ||
| 3028 | -(int)sizeof(__u32), | ||
| 3029 | }, | ||
| 3030 | [BPF_PROG_INFO_JITED_KSYMS] = { | ||
| 3031 | offsetof(struct bpf_prog_info, jited_ksyms), | ||
| 3032 | offsetof(struct bpf_prog_info, nr_jited_ksyms), | ||
| 3033 | -(int)sizeof(__u64), | ||
| 3034 | }, | ||
| 3035 | [BPF_PROG_INFO_JITED_FUNC_LENS] = { | ||
| 3036 | offsetof(struct bpf_prog_info, jited_func_lens), | ||
| 3037 | offsetof(struct bpf_prog_info, nr_jited_func_lens), | ||
| 3038 | -(int)sizeof(__u32), | ||
| 3039 | }, | ||
| 3040 | [BPF_PROG_INFO_FUNC_INFO] = { | ||
| 3041 | offsetof(struct bpf_prog_info, func_info), | ||
| 3042 | offsetof(struct bpf_prog_info, nr_func_info), | ||
| 3043 | offsetof(struct bpf_prog_info, func_info_rec_size), | ||
| 3044 | }, | ||
| 3045 | [BPF_PROG_INFO_LINE_INFO] = { | ||
| 3046 | offsetof(struct bpf_prog_info, line_info), | ||
| 3047 | offsetof(struct bpf_prog_info, nr_line_info), | ||
| 3048 | offsetof(struct bpf_prog_info, line_info_rec_size), | ||
| 3049 | }, | ||
| 3050 | [BPF_PROG_INFO_JITED_LINE_INFO] = { | ||
| 3051 | offsetof(struct bpf_prog_info, jited_line_info), | ||
| 3052 | offsetof(struct bpf_prog_info, nr_jited_line_info), | ||
| 3053 | offsetof(struct bpf_prog_info, jited_line_info_rec_size), | ||
| 3054 | }, | ||
| 3055 | [BPF_PROG_INFO_PROG_TAGS] = { | ||
| 3056 | offsetof(struct bpf_prog_info, prog_tags), | ||
| 3057 | offsetof(struct bpf_prog_info, nr_prog_tags), | ||
| 3058 | -(int)sizeof(__u8) * BPF_TAG_SIZE, | ||
| 3059 | }, | ||
| 3060 | |||
| 3061 | }; | ||
| 3062 | |||
| 3063 | static __u32 bpf_prog_info_read_offset_u32(struct bpf_prog_info *info, int offset) | ||
| 3064 | { | ||
| 3065 | __u32 *array = (__u32 *)info; | ||
| 3066 | |||
| 3067 | if (offset >= 0) | ||
| 3068 | return array[offset / sizeof(__u32)]; | ||
| 3069 | return -(int)offset; | ||
| 3070 | } | ||
| 3071 | |||
| 3072 | static __u64 bpf_prog_info_read_offset_u64(struct bpf_prog_info *info, int offset) | ||
| 3073 | { | ||
| 3074 | __u64 *array = (__u64 *)info; | ||
| 3075 | |||
| 3076 | if (offset >= 0) | ||
| 3077 | return array[offset / sizeof(__u64)]; | ||
| 3078 | return -(int)offset; | ||
| 3079 | } | ||
| 3080 | |||
| 3081 | static void bpf_prog_info_set_offset_u32(struct bpf_prog_info *info, int offset, | ||
| 3082 | __u32 val) | ||
| 3083 | { | ||
| 3084 | __u32 *array = (__u32 *)info; | ||
| 3085 | |||
| 3086 | if (offset >= 0) | ||
| 3087 | array[offset / sizeof(__u32)] = val; | ||
| 3088 | } | ||
| 3089 | |||
| 3090 | static void bpf_prog_info_set_offset_u64(struct bpf_prog_info *info, int offset, | ||
| 3091 | __u64 val) | ||
| 3092 | { | ||
| 3093 | __u64 *array = (__u64 *)info; | ||
| 3094 | |||
| 3095 | if (offset >= 0) | ||
| 3096 | array[offset / sizeof(__u64)] = val; | ||
| 3097 | } | ||
| 3098 | |||
| 3099 | struct bpf_prog_info_linear * | ||
| 3100 | bpf_program__get_prog_info_linear(int fd, __u64 arrays) | ||
| 3101 | { | ||
| 3102 | struct bpf_prog_info_linear *info_linear; | ||
| 3103 | struct bpf_prog_info info = {}; | ||
| 3104 | __u32 info_len = sizeof(info); | ||
| 3105 | __u32 data_len = 0; | ||
| 3106 | int i, err; | ||
| 3107 | void *ptr; | ||
| 3108 | |||
| 3109 | if (arrays >> BPF_PROG_INFO_LAST_ARRAY) | ||
| 3110 | return ERR_PTR(-EINVAL); | ||
| 3111 | |||
| 3112 | /* step 1: get array dimensions */ | ||
| 3113 | err = bpf_obj_get_info_by_fd(fd, &info, &info_len); | ||
| 3114 | if (err) { | ||
| 3115 | pr_debug("can't get prog info: %s", strerror(errno)); | ||
| 3116 | return ERR_PTR(-EFAULT); | ||
| 3117 | } | ||
| 3118 | |||
| 3119 | /* step 2: calculate total size of all arrays */ | ||
| 3120 | for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) { | ||
| 3121 | bool include_array = (arrays & (1UL << i)) > 0; | ||
| 3122 | struct bpf_prog_info_array_desc *desc; | ||
| 3123 | __u32 count, size; | ||
| 3124 | |||
| 3125 | desc = bpf_prog_info_array_desc + i; | ||
| 3126 | |||
| 3127 | /* kernel is too old to support this field */ | ||
| 3128 | if (info_len < desc->array_offset + sizeof(__u32) || | ||
| 3129 | info_len < desc->count_offset + sizeof(__u32) || | ||
| 3130 | (desc->size_offset > 0 && info_len < desc->size_offset)) | ||
| 3131 | include_array = false; | ||
| 3132 | |||
| 3133 | if (!include_array) { | ||
| 3134 | arrays &= ~(1UL << i); /* clear the bit */ | ||
| 3135 | continue; | ||
| 3136 | } | ||
| 3137 | |||
| 3138 | count = bpf_prog_info_read_offset_u32(&info, desc->count_offset); | ||
| 3139 | size = bpf_prog_info_read_offset_u32(&info, desc->size_offset); | ||
| 3140 | |||
| 3141 | data_len += count * size; | ||
| 3142 | } | ||
| 3143 | |||
| 3144 | /* step 3: allocate continuous memory */ | ||
| 3145 | data_len = roundup(data_len, sizeof(__u64)); | ||
| 3146 | info_linear = malloc(sizeof(struct bpf_prog_info_linear) + data_len); | ||
| 3147 | if (!info_linear) | ||
| 3148 | return ERR_PTR(-ENOMEM); | ||
| 3149 | |||
| 3150 | /* step 4: fill data to info_linear->info */ | ||
| 3151 | info_linear->arrays = arrays; | ||
| 3152 | memset(&info_linear->info, 0, sizeof(info)); | ||
| 3153 | ptr = info_linear->data; | ||
| 3154 | |||
| 3155 | for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) { | ||
| 3156 | struct bpf_prog_info_array_desc *desc; | ||
| 3157 | __u32 count, size; | ||
| 3158 | |||
| 3159 | if ((arrays & (1UL << i)) == 0) | ||
| 3160 | continue; | ||
| 3161 | |||
| 3162 | desc = bpf_prog_info_array_desc + i; | ||
| 3163 | count = bpf_prog_info_read_offset_u32(&info, desc->count_offset); | ||
| 3164 | size = bpf_prog_info_read_offset_u32(&info, desc->size_offset); | ||
| 3165 | bpf_prog_info_set_offset_u32(&info_linear->info, | ||
| 3166 | desc->count_offset, count); | ||
| 3167 | bpf_prog_info_set_offset_u32(&info_linear->info, | ||
| 3168 | desc->size_offset, size); | ||
| 3169 | bpf_prog_info_set_offset_u64(&info_linear->info, | ||
| 3170 | desc->array_offset, | ||
| 3171 | ptr_to_u64(ptr)); | ||
| 3172 | ptr += count * size; | ||
| 3173 | } | ||
| 3174 | |||
| 3175 | /* step 5: call syscall again to get required arrays */ | ||
| 3176 | err = bpf_obj_get_info_by_fd(fd, &info_linear->info, &info_len); | ||
| 3177 | if (err) { | ||
| 3178 | pr_debug("can't get prog info: %s", strerror(errno)); | ||
| 3179 | free(info_linear); | ||
| 3180 | return ERR_PTR(-EFAULT); | ||
| 3181 | } | ||
| 3182 | |||
| 3183 | /* step 6: verify the data */ | ||
| 3184 | for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) { | ||
| 3185 | struct bpf_prog_info_array_desc *desc; | ||
| 3186 | __u32 v1, v2; | ||
| 3187 | < | ||
