|
29 | 29 | #include "main.h"
|
30 | 30 | #include "xlated_dumper.h"
|
31 | 31 |
|
| 32 | +#define BPF_METADATA_PREFIX "bpf_metadata_" |
| 33 | +#define BPF_METADATA_PREFIX_LEN strlen(BPF_METADATA_PREFIX) |
| 34 | + |
32 | 35 | const char * const prog_type_name[] = {
|
33 | 36 | [BPF_PROG_TYPE_UNSPEC] = "unspec",
|
34 | 37 | [BPF_PROG_TYPE_SOCKET_FILTER] = "socket_filter",
|
@@ -151,6 +154,221 @@ static void show_prog_maps(int fd, __u32 num_maps)
|
151 | 154 | }
|
152 | 155 | }
|
153 | 156 |
|
| 157 | +static int bpf_prog_find_metadata(int prog_fd, int *map_id) |
| 158 | +{ |
| 159 | + struct bpf_prog_info prog_info = {}; |
| 160 | + struct bpf_map_info map_info; |
| 161 | + __u32 prog_info_len; |
| 162 | + __u32 map_info_len; |
| 163 | + int saved_errno; |
| 164 | + __u32 *map_ids; |
| 165 | + int nr_maps; |
| 166 | + int map_fd; |
| 167 | + int ret; |
| 168 | + __u32 i; |
| 169 | + |
| 170 | + prog_info_len = sizeof(prog_info); |
| 171 | + |
| 172 | + ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); |
| 173 | + if (ret) |
| 174 | + return ret; |
| 175 | + |
| 176 | + if (!prog_info.nr_map_ids) { |
| 177 | + errno = ENOENT; |
| 178 | + return -1; |
| 179 | + } |
| 180 | + |
| 181 | + map_ids = calloc(prog_info.nr_map_ids, sizeof(__u32)); |
| 182 | + if (!map_ids) { |
| 183 | + errno = ENOMEM; |
| 184 | + return -1; |
| 185 | + } |
| 186 | + |
| 187 | + nr_maps = prog_info.nr_map_ids; |
| 188 | + memset(&prog_info, 0, sizeof(prog_info)); |
| 189 | + prog_info.nr_map_ids = nr_maps; |
| 190 | + prog_info.map_ids = ptr_to_u64(map_ids); |
| 191 | + prog_info_len = sizeof(prog_info); |
| 192 | + |
| 193 | + ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); |
| 194 | + if (ret) |
| 195 | + goto free_map_ids; |
| 196 | + |
| 197 | + for (i = 0; i < prog_info.nr_map_ids; i++) { |
| 198 | + map_fd = bpf_map_get_fd_by_id(map_ids[i]); |
| 199 | + if (map_fd < 0) { |
| 200 | + ret = -1; |
| 201 | + goto free_map_ids; |
| 202 | + } |
| 203 | + |
| 204 | + memset(&map_info, 0, sizeof(map_info)); |
| 205 | + map_info_len = sizeof(map_info); |
| 206 | + ret = bpf_obj_get_info_by_fd(map_fd, &map_info, &map_info_len); |
| 207 | + |
| 208 | + saved_errno = errno; |
| 209 | + close(map_fd); |
| 210 | + errno = saved_errno; |
| 211 | + if (ret) |
| 212 | + goto free_map_ids; |
| 213 | + |
| 214 | + if (map_info.type != BPF_MAP_TYPE_ARRAY) |
| 215 | + continue; |
| 216 | + if (map_info.key_size != sizeof(int)) |
| 217 | + continue; |
| 218 | + if (map_info.max_entries != 1) |
| 219 | + continue; |
| 220 | + if (!map_info.btf_value_type_id) |
| 221 | + continue; |
| 222 | + if (!strstr(map_info.name, ".rodata")) |
| 223 | + continue; |
| 224 | + |
| 225 | + *map_id = map_ids[i]; |
| 226 | + goto free_map_ids; |
| 227 | + } |
| 228 | + |
| 229 | + ret = -1; |
| 230 | + errno = ENOENT; |
| 231 | + |
| 232 | +free_map_ids: |
| 233 | + saved_errno = errno; |
| 234 | + free(map_ids); |
| 235 | + errno = saved_errno; |
| 236 | + return ret; |
| 237 | +} |
| 238 | + |
| 239 | +static bool has_metadata_prefix(const char *s) |
| 240 | +{ |
| 241 | + return strstr(s, BPF_METADATA_PREFIX) == s; |
| 242 | +} |
| 243 | + |
| 244 | +static void show_prog_metadata(int fd, __u32 num_maps) |
| 245 | +{ |
| 246 | + const struct btf_type *t_datasec, *t_var; |
| 247 | + struct bpf_map_info map_info = {}; |
| 248 | + struct btf_var_secinfo *vsi; |
| 249 | + bool printed_header = false; |
| 250 | + struct btf *btf = NULL; |
| 251 | + unsigned int i, vlen; |
| 252 | + __u32 map_info_len; |
| 253 | + void *value = NULL; |
| 254 | + const char *name; |
| 255 | + int map_id = 0; |
| 256 | + int key = 0; |
| 257 | + int map_fd; |
| 258 | + int err; |
| 259 | + |
| 260 | + if (!num_maps) |
| 261 | + return; |
| 262 | + |
| 263 | + err = bpf_prog_find_metadata(fd, &map_id); |
| 264 | + if (err < 0) |
| 265 | + return; |
| 266 | + |
| 267 | + map_fd = bpf_map_get_fd_by_id(map_id); |
| 268 | + if (map_fd < 0) |
| 269 | + return; |
| 270 | + |
| 271 | + map_info_len = sizeof(map_info); |
| 272 | + err = bpf_obj_get_info_by_fd(map_fd, &map_info, &map_info_len); |
| 273 | + if (err) |
| 274 | + goto out_close; |
| 275 | + |
| 276 | + value = malloc(map_info.value_size); |
| 277 | + if (!value) |
| 278 | + goto out_close; |
| 279 | + |
| 280 | + if (bpf_map_lookup_elem(map_fd, &key, value)) |
| 281 | + goto out_free; |
| 282 | + |
| 283 | + err = btf__get_from_id(map_info.btf_id, &btf); |
| 284 | + if (err || !btf) |
| 285 | + goto out_free; |
| 286 | + |
| 287 | + t_datasec = btf__type_by_id(btf, map_info.btf_value_type_id); |
| 288 | + if (!btf_is_datasec(t_datasec)) |
| 289 | + goto out_free; |
| 290 | + |
| 291 | + vlen = btf_vlen(t_datasec); |
| 292 | + vsi = btf_var_secinfos(t_datasec); |
| 293 | + |
| 294 | + /* We don't proceed to check the kinds of the elements of the DATASEC. |
| 295 | + * The verifier enforces them to be BTF_KIND_VAR. |
| 296 | + */ |
| 297 | + |
| 298 | + if (json_output) { |
| 299 | + struct btf_dumper d = { |
| 300 | + .btf = btf, |
| 301 | + .jw = json_wtr, |
| 302 | + .is_plain_text = false, |
| 303 | + }; |
| 304 | + |
| 305 | + for (i = 0; i < vlen; i++, vsi++) { |
| 306 | + t_var = btf__type_by_id(btf, vsi->type); |
| 307 | + name = btf__name_by_offset(btf, t_var->name_off); |
| 308 | + |
| 309 | + if (!has_metadata_prefix(name)) |
| 310 | + continue; |
| 311 | + |
| 312 | + if (!printed_header) { |
| 313 | + jsonw_name(json_wtr, "metadata"); |
| 314 | + jsonw_start_object(json_wtr); |
| 315 | + printed_header = true; |
| 316 | + } |
| 317 | + |
| 318 | + jsonw_name(json_wtr, name + BPF_METADATA_PREFIX_LEN); |
| 319 | + err = btf_dumper_type(&d, t_var->type, value + vsi->offset); |
| 320 | + if (err) { |
| 321 | + p_err("btf dump failed: %d", err); |
| 322 | + break; |
| 323 | + } |
| 324 | + } |
| 325 | + if (printed_header) |
| 326 | + jsonw_end_object(json_wtr); |
| 327 | + } else { |
| 328 | + json_writer_t *btf_wtr = jsonw_new(stdout); |
| 329 | + struct btf_dumper d = { |
| 330 | + .btf = btf, |
| 331 | + .jw = btf_wtr, |
| 332 | + .is_plain_text = true, |
| 333 | + }; |
| 334 | + if (!btf_wtr) { |
| 335 | + p_err("jsonw alloc failed"); |
| 336 | + goto out_free; |
| 337 | + } |
| 338 | + |
| 339 | + for (i = 0; i < vlen; i++, vsi++) { |
| 340 | + t_var = btf__type_by_id(btf, vsi->type); |
| 341 | + name = btf__name_by_offset(btf, t_var->name_off); |
| 342 | + |
| 343 | + if (!has_metadata_prefix(name)) |
| 344 | + continue; |
| 345 | + |
| 346 | + if (!printed_header) { |
| 347 | + printf("\tmetadata:"); |
| 348 | + printed_header = true; |
| 349 | + } |
| 350 | + |
| 351 | + printf("\n\t\t%s = ", name + BPF_METADATA_PREFIX_LEN); |
| 352 | + |
| 353 | + jsonw_reset(btf_wtr); |
| 354 | + err = btf_dumper_type(&d, t_var->type, value + vsi->offset); |
| 355 | + if (err) { |
| 356 | + p_err("btf dump failed: %d", err); |
| 357 | + break; |
| 358 | + } |
| 359 | + } |
| 360 | + if (printed_header) |
| 361 | + jsonw_destroy(&btf_wtr); |
| 362 | + } |
| 363 | + |
| 364 | +out_free: |
| 365 | + btf__free(btf); |
| 366 | + free(value); |
| 367 | + |
| 368 | +out_close: |
| 369 | + close(map_fd); |
| 370 | +} |
| 371 | + |
154 | 372 | static void print_prog_header_json(struct bpf_prog_info *info)
|
155 | 373 | {
|
156 | 374 | jsonw_uint_field(json_wtr, "id", info->id);
|
@@ -228,6 +446,8 @@ static void print_prog_json(struct bpf_prog_info *info, int fd)
|
228 | 446 |
|
229 | 447 | emit_obj_refs_json(&refs_table, info->id, json_wtr);
|
230 | 448 |
|
| 449 | + show_prog_metadata(fd, info->nr_map_ids); |
| 450 | + |
231 | 451 | jsonw_end_object(json_wtr);
|
232 | 452 | }
|
233 | 453 |
|
@@ -297,6 +517,8 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd)
|
297 | 517 | emit_obj_refs_plain(&refs_table, info->id, "\n\tpids ");
|
298 | 518 |
|
299 | 519 | printf("\n");
|
| 520 | + |
| 521 | + show_prog_metadata(fd, info->nr_map_ids); |
300 | 522 | }
|
301 | 523 |
|
302 | 524 | static int show_prog(int fd)
|
|
0 commit comments