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