blob: 59833125ac0a13a55f8c54e5a52b3082424000f8 [file] [log] [blame]
Andrii Nakryikoc93cc692019-04-25 15:30:08 -07001// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2/* Copyright (C) 2019 Facebook */
3
4#include <errno.h>
5#include <fcntl.h>
6#include <linux/err.h>
7#include <stdbool.h>
8#include <stdio.h>
9#include <string.h>
10#include <unistd.h>
Andrii Nakryikoc93cc692019-04-25 15:30:08 -070011#include <linux/btf.h>
Jiri Olsaa9436462019-10-24 15:30:25 +020012#include <sys/types.h>
13#include <sys/stat.h>
Andrii Nakryikoc93cc692019-04-25 15:30:08 -070014
Quentin Monnet2828d0d2021-10-23 21:51:53 +010015#include <bpf/bpf.h>
16#include <bpf/btf.h>
17#include <bpf/hashmap.h>
18#include <bpf/libbpf.h>
19
Andrii Nakryikoc93cc692019-04-25 15:30:08 -070020#include "json_writer.h"
21#include "main.h"
22
23static const char * const btf_kind_str[NR_BTF_KINDS] = {
24 [BTF_KIND_UNKN] = "UNKNOWN",
25 [BTF_KIND_INT] = "INT",
26 [BTF_KIND_PTR] = "PTR",
27 [BTF_KIND_ARRAY] = "ARRAY",
28 [BTF_KIND_STRUCT] = "STRUCT",
29 [BTF_KIND_UNION] = "UNION",
30 [BTF_KIND_ENUM] = "ENUM",
31 [BTF_KIND_FWD] = "FWD",
32 [BTF_KIND_TYPEDEF] = "TYPEDEF",
33 [BTF_KIND_VOLATILE] = "VOLATILE",
34 [BTF_KIND_CONST] = "CONST",
35 [BTF_KIND_RESTRICT] = "RESTRICT",
36 [BTF_KIND_FUNC] = "FUNC",
37 [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO",
38 [BTF_KIND_VAR] = "VAR",
39 [BTF_KIND_DATASEC] = "DATASEC",
Ilya Leoshkevich737e0f92021-02-26 21:22:50 +010040 [BTF_KIND_FLOAT] = "FLOAT",
Yonghong Song223f9032021-10-12 09:48:38 -070041 [BTF_KIND_DECL_TAG] = "DECL_TAG",
Yonghong Song3da5ba62021-11-11 17:26:20 -080042 [BTF_KIND_TYPE_TAG] = "TYPE_TAG",
Andrii Nakryikoc93cc692019-04-25 15:30:08 -070043};
44
Quentin Monnet4d374ba02019-08-20 10:31:54 +010045struct btf_attach_point {
46 __u32 obj_id;
47 __u32 btf_id;
Quentin Monnet4d374ba02019-08-20 10:31:54 +010048};
49
Andrii Nakryikoc93cc692019-04-25 15:30:08 -070050static const char *btf_int_enc_str(__u8 encoding)
51{
52 switch (encoding) {
53 case 0:
54 return "(none)";
55 case BTF_INT_SIGNED:
56 return "SIGNED";
57 case BTF_INT_CHAR:
58 return "CHAR";
59 case BTF_INT_BOOL:
60 return "BOOL";
61 default:
62 return "UNKN";
63 }
64}
65
66static const char *btf_var_linkage_str(__u32 linkage)
67{
68 switch (linkage) {
69 case BTF_VAR_STATIC:
70 return "static";
71 case BTF_VAR_GLOBAL_ALLOCATED:
Andrii Nakryiko0dd7e452021-04-23 11:13:31 -070072 return "global";
73 case BTF_VAR_GLOBAL_EXTERN:
74 return "extern";
Andrii Nakryikoc93cc692019-04-25 15:30:08 -070075 default:
76 return "(unknown)";
77 }
78}
79
Andrii Nakryiko41258282020-01-23 21:43:17 -080080static const char *btf_func_linkage_str(const struct btf_type *t)
81{
82 switch (btf_vlen(t)) {
83 case BTF_FUNC_STATIC:
84 return "static";
85 case BTF_FUNC_GLOBAL:
86 return "global";
87 case BTF_FUNC_EXTERN:
88 return "extern";
89 default:
90 return "(unknown)";
91 }
92}
93
Andrii Nakryikoc93cc692019-04-25 15:30:08 -070094static const char *btf_str(const struct btf *btf, __u32 off)
95{
96 if (!off)
97 return "(anon)";
98 return btf__name_by_offset(btf, off) ? : "(invalid)";
99}
100
Andrii Nakryiko5b438f02021-04-23 11:13:32 -0700101static int btf_kind_safe(int kind)
102{
103 return kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN;
104}
105
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700106static int dump_btf_type(const struct btf *btf, __u32 id,
107 const struct btf_type *t)
108{
109 json_writer_t *w = json_wtr;
Andrii Nakryiko5b438f02021-04-23 11:13:32 -0700110 int kind = btf_kind(t);
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700111
112 if (json_output) {
113 jsonw_start_object(w);
114 jsonw_uint_field(w, "id", id);
Andrii Nakryiko5b438f02021-04-23 11:13:32 -0700115 jsonw_string_field(w, "kind", btf_kind_str[btf_kind_safe(kind)]);
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700116 jsonw_string_field(w, "name", btf_str(btf, t->name_off));
117 } else {
Andrii Nakryiko5b438f02021-04-23 11:13:32 -0700118 printf("[%u] %s '%s'", id, btf_kind_str[btf_kind_safe(kind)],
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700119 btf_str(btf, t->name_off));
120 }
121
Andrii Nakryiko5b438f02021-04-23 11:13:32 -0700122 switch (kind) {
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700123 case BTF_KIND_INT: {
124 __u32 v = *(__u32 *)(t + 1);
125 const char *enc;
126
127 enc = btf_int_enc_str(BTF_INT_ENCODING(v));
128
129 if (json_output) {
130 jsonw_uint_field(w, "size", t->size);
131 jsonw_uint_field(w, "bits_offset", BTF_INT_OFFSET(v));
132 jsonw_uint_field(w, "nr_bits", BTF_INT_BITS(v));
133 jsonw_string_field(w, "encoding", enc);
134 } else {
135 printf(" size=%u bits_offset=%u nr_bits=%u encoding=%s",
136 t->size, BTF_INT_OFFSET(v), BTF_INT_BITS(v),
137 enc);
138 }
139 break;
140 }
141 case BTF_KIND_PTR:
142 case BTF_KIND_CONST:
143 case BTF_KIND_VOLATILE:
144 case BTF_KIND_RESTRICT:
145 case BTF_KIND_TYPEDEF:
Yonghong Song3da5ba62021-11-11 17:26:20 -0800146 case BTF_KIND_TYPE_TAG:
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700147 if (json_output)
148 jsonw_uint_field(w, "type_id", t->type);
149 else
150 printf(" type_id=%u", t->type);
151 break;
152 case BTF_KIND_ARRAY: {
153 const struct btf_array *arr = (const void *)(t + 1);
154
155 if (json_output) {
156 jsonw_uint_field(w, "type_id", arr->type);
157 jsonw_uint_field(w, "index_type_id", arr->index_type);
158 jsonw_uint_field(w, "nr_elems", arr->nelems);
159 } else {
160 printf(" type_id=%u index_type_id=%u nr_elems=%u",
161 arr->type, arr->index_type, arr->nelems);
162 }
163 break;
164 }
165 case BTF_KIND_STRUCT:
166 case BTF_KIND_UNION: {
167 const struct btf_member *m = (const void *)(t + 1);
168 __u16 vlen = BTF_INFO_VLEN(t->info);
169 int i;
170
171 if (json_output) {
172 jsonw_uint_field(w, "size", t->size);
173 jsonw_uint_field(w, "vlen", vlen);
174 jsonw_name(w, "members");
175 jsonw_start_array(w);
176 } else {
177 printf(" size=%u vlen=%u", t->size, vlen);
178 }
179 for (i = 0; i < vlen; i++, m++) {
180 const char *name = btf_str(btf, m->name_off);
181 __u32 bit_off, bit_sz;
182
183 if (BTF_INFO_KFLAG(t->info)) {
184 bit_off = BTF_MEMBER_BIT_OFFSET(m->offset);
185 bit_sz = BTF_MEMBER_BITFIELD_SIZE(m->offset);
186 } else {
187 bit_off = m->offset;
188 bit_sz = 0;
189 }
190
191 if (json_output) {
192 jsonw_start_object(w);
193 jsonw_string_field(w, "name", name);
194 jsonw_uint_field(w, "type_id", m->type);
195 jsonw_uint_field(w, "bits_offset", bit_off);
196 if (bit_sz) {
197 jsonw_uint_field(w, "bitfield_size",
198 bit_sz);
199 }
200 jsonw_end_object(w);
201 } else {
202 printf("\n\t'%s' type_id=%u bits_offset=%u",
203 name, m->type, bit_off);
204 if (bit_sz)
205 printf(" bitfield_size=%u", bit_sz);
206 }
207 }
208 if (json_output)
209 jsonw_end_array(w);
210 break;
211 }
212 case BTF_KIND_ENUM: {
213 const struct btf_enum *v = (const void *)(t + 1);
214 __u16 vlen = BTF_INFO_VLEN(t->info);
215 int i;
216
217 if (json_output) {
218 jsonw_uint_field(w, "size", t->size);
219 jsonw_uint_field(w, "vlen", vlen);
220 jsonw_name(w, "values");
221 jsonw_start_array(w);
222 } else {
223 printf(" size=%u vlen=%u", t->size, vlen);
224 }
225 for (i = 0; i < vlen; i++, v++) {
226 const char *name = btf_str(btf, v->name_off);
227
228 if (json_output) {
229 jsonw_start_object(w);
230 jsonw_string_field(w, "name", name);
231 jsonw_uint_field(w, "val", v->val);
232 jsonw_end_object(w);
233 } else {
234 printf("\n\t'%s' val=%u", name, v->val);
235 }
236 }
237 if (json_output)
238 jsonw_end_array(w);
239 break;
240 }
241 case BTF_KIND_FWD: {
Andrii Nakryiko9c3ddee2019-05-16 23:21:29 -0700242 const char *fwd_kind = BTF_INFO_KFLAG(t->info) ? "union"
243 : "struct";
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700244
245 if (json_output)
246 jsonw_string_field(w, "fwd_kind", fwd_kind);
247 else
248 printf(" fwd_kind=%s", fwd_kind);
249 break;
250 }
Andrii Nakryiko41258282020-01-23 21:43:17 -0800251 case BTF_KIND_FUNC: {
252 const char *linkage = btf_func_linkage_str(t);
253
254 if (json_output) {
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700255 jsonw_uint_field(w, "type_id", t->type);
Andrii Nakryiko41258282020-01-23 21:43:17 -0800256 jsonw_string_field(w, "linkage", linkage);
257 } else {
258 printf(" type_id=%u linkage=%s", t->type, linkage);
259 }
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700260 break;
Andrii Nakryiko41258282020-01-23 21:43:17 -0800261 }
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700262 case BTF_KIND_FUNC_PROTO: {
263 const struct btf_param *p = (const void *)(t + 1);
264 __u16 vlen = BTF_INFO_VLEN(t->info);
265 int i;
266
267 if (json_output) {
268 jsonw_uint_field(w, "ret_type_id", t->type);
269 jsonw_uint_field(w, "vlen", vlen);
270 jsonw_name(w, "params");
271 jsonw_start_array(w);
272 } else {
273 printf(" ret_type_id=%u vlen=%u", t->type, vlen);
274 }
275 for (i = 0; i < vlen; i++, p++) {
276 const char *name = btf_str(btf, p->name_off);
277
278 if (json_output) {
279 jsonw_start_object(w);
280 jsonw_string_field(w, "name", name);
281 jsonw_uint_field(w, "type_id", p->type);
282 jsonw_end_object(w);
283 } else {
284 printf("\n\t'%s' type_id=%u", name, p->type);
285 }
286 }
287 if (json_output)
288 jsonw_end_array(w);
289 break;
290 }
291 case BTF_KIND_VAR: {
292 const struct btf_var *v = (const void *)(t + 1);
293 const char *linkage;
294
295 linkage = btf_var_linkage_str(v->linkage);
296
297 if (json_output) {
298 jsonw_uint_field(w, "type_id", t->type);
299 jsonw_string_field(w, "linkage", linkage);
300 } else {
301 printf(" type_id=%u, linkage=%s", t->type, linkage);
302 }
303 break;
304 }
305 case BTF_KIND_DATASEC: {
Andrii Nakryiko5b438f02021-04-23 11:13:32 -0700306 const struct btf_var_secinfo *v = (const void *)(t + 1);
307 const struct btf_type *vt;
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700308 __u16 vlen = BTF_INFO_VLEN(t->info);
309 int i;
310
311 if (json_output) {
312 jsonw_uint_field(w, "size", t->size);
313 jsonw_uint_field(w, "vlen", vlen);
314 jsonw_name(w, "vars");
315 jsonw_start_array(w);
316 } else {
317 printf(" size=%u vlen=%u", t->size, vlen);
318 }
319 for (i = 0; i < vlen; i++, v++) {
320 if (json_output) {
321 jsonw_start_object(w);
322 jsonw_uint_field(w, "type_id", v->type);
323 jsonw_uint_field(w, "offset", v->offset);
324 jsonw_uint_field(w, "size", v->size);
325 jsonw_end_object(w);
326 } else {
327 printf("\n\ttype_id=%u offset=%u size=%u",
328 v->type, v->offset, v->size);
Andrii Nakryiko5b438f02021-04-23 11:13:32 -0700329
Hengqi Chen58fc1552021-10-22 21:06:22 +0800330 if (v->type < btf__type_cnt(btf)) {
Andrii Nakryiko5b438f02021-04-23 11:13:32 -0700331 vt = btf__type_by_id(btf, v->type);
332 printf(" (%s '%s')",
333 btf_kind_str[btf_kind_safe(btf_kind(vt))],
334 btf_str(btf, vt->name_off));
335 }
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700336 }
337 }
338 if (json_output)
339 jsonw_end_array(w);
340 break;
341 }
Ilya Leoshkevich737e0f92021-02-26 21:22:50 +0100342 case BTF_KIND_FLOAT: {
343 if (json_output)
344 jsonw_uint_field(w, "size", t->size);
345 else
346 printf(" size=%u", t->size);
347 break;
348 }
Yonghong Song223f9032021-10-12 09:48:38 -0700349 case BTF_KIND_DECL_TAG: {
350 const struct btf_decl_tag *tag = (const void *)(t + 1);
Yonghong Song5c07f2f2021-09-14 15:30:31 -0700351
352 if (json_output) {
353 jsonw_uint_field(w, "type_id", t->type);
354 jsonw_int_field(w, "component_idx", tag->component_idx);
355 } else {
356 printf(" type_id=%u component_idx=%d", t->type, tag->component_idx);
357 }
358 break;
359 }
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700360 default:
361 break;
362 }
363
364 if (json_output)
365 jsonw_end_object(json_wtr);
366 else
367 printf("\n");
368
369 return 0;
370}
371
372static int dump_btf_raw(const struct btf *btf,
373 __u32 *root_type_ids, int root_type_cnt)
374{
375 const struct btf_type *t;
376 int i;
377
378 if (json_output) {
379 jsonw_start_object(json_wtr);
380 jsonw_name(json_wtr, "types");
381 jsonw_start_array(json_wtr);
382 }
383
384 if (root_type_cnt) {
385 for (i = 0; i < root_type_cnt; i++) {
386 t = btf__type_by_id(btf, root_type_ids[i]);
387 dump_btf_type(btf, root_type_ids[i], t);
388 }
389 } else {
Andrii Nakryikofa452832020-12-01 22:52:43 -0800390 const struct btf *base;
Hengqi Chen58fc1552021-10-22 21:06:22 +0800391 int cnt = btf__type_cnt(btf);
Andrii Nakryiko75fa1772020-11-04 20:34:01 -0800392 int start_id = 1;
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700393
Andrii Nakryikofa452832020-12-01 22:52:43 -0800394 base = btf__base_btf(btf);
395 if (base)
Hengqi Chen58fc1552021-10-22 21:06:22 +0800396 start_id = btf__type_cnt(base);
Andrii Nakryiko75fa1772020-11-04 20:34:01 -0800397
Hengqi Chen58fc1552021-10-22 21:06:22 +0800398 for (i = start_id; i < cnt; i++) {
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700399 t = btf__type_by_id(btf, i);
400 dump_btf_type(btf, i, t);
401 }
402 }
403
404 if (json_output) {
405 jsonw_end_array(json_wtr);
406 jsonw_end_object(json_wtr);
407 }
408 return 0;
409}
410
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700411static void __printf(2, 0) btf_dump_printf(void *ctx,
412 const char *fmt, va_list args)
413{
414 vfprintf(stdout, fmt, args);
415}
416
417static int dump_btf_c(const struct btf *btf,
418 __u32 *root_type_ids, int root_type_cnt)
419{
420 struct btf_dump *d;
421 int err = 0, i;
422
Andrii Nakryiko164b04f2021-11-10 21:36:24 -0800423 d = btf_dump__new(btf, btf_dump_printf, NULL, NULL);
Hengqi Chene5043892021-11-15 09:24:36 +0800424 err = libbpf_get_error(d);
425 if (err)
426 return err;
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700427
Andrii Nakryikoca7dc272020-02-29 15:11:09 -0800428 printf("#ifndef __VMLINUX_H__\n");
429 printf("#define __VMLINUX_H__\n");
430 printf("\n");
Andrii Nakryiko1cf5b232020-01-12 23:31:41 -0800431 printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
432 printf("#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)\n");
433 printf("#endif\n\n");
434
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700435 if (root_type_cnt) {
436 for (i = 0; i < root_type_cnt; i++) {
437 err = btf_dump__dump_type(d, root_type_ids[i]);
438 if (err)
439 goto done;
440 }
441 } else {
Hengqi Chen58fc1552021-10-22 21:06:22 +0800442 int cnt = btf__type_cnt(btf);
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700443
Hengqi Chen58fc1552021-10-22 21:06:22 +0800444 for (i = 1; i < cnt; i++) {
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700445 err = btf_dump__dump_type(d, i);
446 if (err)
447 goto done;
448 }
449 }
450
Andrii Nakryiko1cf5b232020-01-12 23:31:41 -0800451 printf("#ifndef BPF_NO_PRESERVE_ACCESS_INDEX\n");
452 printf("#pragma clang attribute pop\n");
453 printf("#endif\n");
Andrii Nakryikoca7dc272020-02-29 15:11:09 -0800454 printf("\n");
455 printf("#endif /* __VMLINUX_H__ */\n");
Andrii Nakryiko1cf5b232020-01-12 23:31:41 -0800456
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700457done:
458 btf_dump__free(d);
459 return err;
460}
461
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700462static int do_dump(int argc, char **argv)
463{
Andrii Nakryikofa452832020-12-01 22:52:43 -0800464 struct btf *btf = NULL, *base = NULL;
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700465 __u32 root_type_ids[2];
466 int root_type_cnt = 0;
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700467 bool dump_c = false;
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700468 __u32 btf_id = -1;
469 const char *src;
470 int fd = -1;
471 int err;
472
473 if (!REQ_ARGS(2)) {
474 usage();
475 return -1;
476 }
477 src = GET_ARG();
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700478 if (is_prefix(src, "map")) {
479 struct bpf_map_info info = {};
480 __u32 len = sizeof(info);
481
482 if (!REQ_ARGS(2)) {
483 usage();
484 return -1;
485 }
486
487 fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
488 if (fd < 0)
489 return -1;
490
491 btf_id = info.btf_id;
492 if (argc && is_prefix(*argv, "key")) {
493 root_type_ids[root_type_cnt++] = info.btf_key_type_id;
494 NEXT_ARG();
495 } else if (argc && is_prefix(*argv, "value")) {
496 root_type_ids[root_type_cnt++] = info.btf_value_type_id;
497 NEXT_ARG();
498 } else if (argc && is_prefix(*argv, "all")) {
499 NEXT_ARG();
500 } else if (argc && is_prefix(*argv, "kv")) {
501 root_type_ids[root_type_cnt++] = info.btf_key_type_id;
502 root_type_ids[root_type_cnt++] = info.btf_value_type_id;
503 NEXT_ARG();
504 } else {
505 root_type_ids[root_type_cnt++] = info.btf_key_type_id;
506 root_type_ids[root_type_cnt++] = info.btf_value_type_id;
507 }
508 } else if (is_prefix(src, "prog")) {
509 struct bpf_prog_info info = {};
510 __u32 len = sizeof(info);
511
512 if (!REQ_ARGS(2)) {
513 usage();
514 return -1;
515 }
516
517 fd = prog_parse_fd(&argc, &argv);
518 if (fd < 0)
519 return -1;
520
521 err = bpf_obj_get_info_by_fd(fd, &info, &len);
522 if (err) {
523 p_err("can't get prog info: %s", strerror(errno));
524 goto done;
525 }
526
527 btf_id = info.btf_id;
528 } else if (is_prefix(src, "id")) {
529 char *endptr;
530
531 btf_id = strtoul(*argv, &endptr, 0);
532 if (*endptr) {
Quentin Monneted4a3982019-08-15 15:32:17 +0100533 p_err("can't parse %s as ID", *argv);
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700534 return -1;
535 }
536 NEXT_ARG();
537 } else if (is_prefix(src, "file")) {
Andrii Nakryikofa452832020-12-01 22:52:43 -0800538 const char sysfs_prefix[] = "/sys/kernel/btf/";
539 const char sysfs_vmlinux[] = "/sys/kernel/btf/vmlinux";
540
541 if (!base_btf &&
542 strncmp(*argv, sysfs_prefix, sizeof(sysfs_prefix) - 1) == 0 &&
543 strcmp(*argv, sysfs_vmlinux) != 0) {
544 base = btf__parse(sysfs_vmlinux, NULL);
545 if (libbpf_get_error(base)) {
546 p_err("failed to parse vmlinux BTF at '%s': %ld\n",
547 sysfs_vmlinux, libbpf_get_error(base));
548 base = NULL;
549 }
550 }
551
552 btf = btf__parse_split(*argv, base ?: base_btf);
Hengqi Chene5043892021-11-15 09:24:36 +0800553 err = libbpf_get_error(btf);
554 if (err) {
Andrii Nakryiko58650cc2019-05-24 11:58:58 -0700555 btf = NULL;
Toke Høiland-Jørgensen229c3b42020-01-20 14:06:46 +0100556 p_err("failed to load BTF from %s: %s",
Andrii Nakryiko58650cc2019-05-24 11:58:58 -0700557 *argv, strerror(err));
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700558 goto done;
Andrii Nakryiko58650cc2019-05-24 11:58:58 -0700559 }
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700560 NEXT_ARG();
561 } else {
562 err = -1;
563 p_err("unrecognized BTF source specifier: '%s'", src);
564 goto done;
565 }
566
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700567 while (argc) {
568 if (is_prefix(*argv, "format")) {
569 NEXT_ARG();
570 if (argc < 1) {
571 p_err("expecting value for 'format' option\n");
Andrii Nakryiko4bbb3582021-03-13 13:09:18 -0800572 err = -EINVAL;
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700573 goto done;
574 }
575 if (strcmp(*argv, "c") == 0) {
576 dump_c = true;
577 } else if (strcmp(*argv, "raw") == 0) {
578 dump_c = false;
579 } else {
580 p_err("unrecognized format specifier: '%s', possible values: raw, c",
581 *argv);
Andrii Nakryiko4bbb3582021-03-13 13:09:18 -0800582 err = -EINVAL;
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700583 goto done;
584 }
585 NEXT_ARG();
586 } else {
587 p_err("unrecognized option: '%s'", *argv);
Andrii Nakryiko4bbb3582021-03-13 13:09:18 -0800588 err = -EINVAL;
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700589 goto done;
590 }
591 }
592
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700593 if (!btf) {
Quentin Monnet211ab782021-07-29 17:20:28 +0100594 btf = btf__load_from_kernel_by_id_split(btf_id, base_btf);
Quentin Monnet86f4b7f2021-07-29 17:20:25 +0100595 err = libbpf_get_error(btf);
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700596 if (err) {
597 p_err("get btf by id (%u): %s", btf_id, strerror(err));
598 goto done;
599 }
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700600 }
601
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700602 if (dump_c) {
603 if (json_output) {
604 p_err("JSON output for C-syntax dump is not supported");
605 err = -ENOTSUP;
606 goto done;
607 }
608 err = dump_btf_c(btf, root_type_ids, root_type_cnt);
609 } else {
610 err = dump_btf_raw(btf, root_type_ids, root_type_cnt);
611 }
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700612
613done:
614 close(fd);
615 btf__free(btf);
Andrii Nakryikofa452832020-12-01 22:52:43 -0800616 btf__free(base);
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700617 return err;
618}
619
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100620static int btf_parse_fd(int *argc, char ***argv)
621{
622 unsigned int id;
623 char *endptr;
624 int fd;
625
626 if (!is_prefix(*argv[0], "id")) {
627 p_err("expected 'id', got: '%s'?", **argv);
628 return -1;
629 }
630 NEXT_ARGP();
631
632 id = strtoul(**argv, &endptr, 0);
633 if (*endptr) {
634 p_err("can't parse %s as ID", **argv);
635 return -1;
636 }
637 NEXT_ARGP();
638
639 fd = bpf_btf_get_fd_by_id(id);
640 if (fd < 0)
641 p_err("can't get BTF object by id (%u): %s",
642 id, strerror(errno));
643
644 return fd;
645}
646
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100647static int
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100648build_btf_type_table(struct hashmap *tab, enum bpf_obj_type type,
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100649 void *info, __u32 *len)
650{
651 static const char * const names[] = {
652 [BPF_OBJ_UNKNOWN] = "unknown",
653 [BPF_OBJ_PROG] = "prog",
654 [BPF_OBJ_MAP] = "map",
655 };
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100656 __u32 btf_id, id = 0;
657 int err;
658 int fd;
659
660 while (true) {
661 switch (type) {
662 case BPF_OBJ_PROG:
663 err = bpf_prog_get_next_id(id, &id);
664 break;
665 case BPF_OBJ_MAP:
666 err = bpf_map_get_next_id(id, &id);
667 break;
668 default:
669 err = -1;
670 p_err("unexpected object type: %d", type);
671 goto err_free;
672 }
673 if (err) {
674 if (errno == ENOENT) {
675 err = 0;
676 break;
677 }
678 p_err("can't get next %s: %s%s", names[type],
679 strerror(errno),
680 errno == EINVAL ? " -- kernel too old?" : "");
681 goto err_free;
682 }
683
684 switch (type) {
685 case BPF_OBJ_PROG:
686 fd = bpf_prog_get_fd_by_id(id);
687 break;
688 case BPF_OBJ_MAP:
689 fd = bpf_map_get_fd_by_id(id);
690 break;
691 default:
692 err = -1;
693 p_err("unexpected object type: %d", type);
694 goto err_free;
695 }
696 if (fd < 0) {
697 if (errno == ENOENT)
698 continue;
699 p_err("can't get %s by id (%u): %s", names[type], id,
700 strerror(errno));
701 err = -1;
702 goto err_free;
703 }
704
705 memset(info, 0, *len);
706 err = bpf_obj_get_info_by_fd(fd, info, len);
707 close(fd);
708 if (err) {
709 p_err("can't get %s info: %s", names[type],
710 strerror(errno));
711 goto err_free;
712 }
713
714 switch (type) {
715 case BPF_OBJ_PROG:
716 btf_id = ((struct bpf_prog_info *)info)->btf_id;
717 break;
718 case BPF_OBJ_MAP:
719 btf_id = ((struct bpf_map_info *)info)->btf_id;
720 break;
721 default:
722 err = -1;
723 p_err("unexpected object type: %d", type);
724 goto err_free;
725 }
726 if (!btf_id)
727 continue;
728
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100729 err = hashmap__append(tab, u32_as_hash_field(btf_id),
730 u32_as_hash_field(id));
731 if (err) {
732 p_err("failed to append entry to hashmap for BTF ID %u, object ID %u: %s",
733 btf_id, id, strerror(errno));
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100734 goto err_free;
735 }
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100736 }
737
738 return 0;
739
740err_free:
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100741 hashmap__free(tab);
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100742 return err;
743}
744
745static int
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100746build_btf_tables(struct hashmap *btf_prog_table,
747 struct hashmap *btf_map_table)
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100748{
749 struct bpf_prog_info prog_info;
750 __u32 prog_len = sizeof(prog_info);
751 struct bpf_map_info map_info;
752 __u32 map_len = sizeof(map_info);
753 int err = 0;
754
755 err = build_btf_type_table(btf_prog_table, BPF_OBJ_PROG, &prog_info,
756 &prog_len);
757 if (err)
758 return err;
759
760 err = build_btf_type_table(btf_map_table, BPF_OBJ_MAP, &map_info,
761 &map_len);
762 if (err) {
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100763 hashmap__free(btf_prog_table);
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100764 return err;
765 }
766
767 return 0;
768}
769
770static void
771show_btf_plain(struct bpf_btf_info *info, int fd,
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100772 struct hashmap *btf_prog_table,
773 struct hashmap *btf_map_table)
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100774{
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100775 struct hashmap_entry *entry;
Andrii Nakryikocecaf4a2020-11-09 17:19:32 -0800776 const char *name = u64_to_ptr(info->name);
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100777 int n;
778
779 printf("%u: ", info->id);
Andrii Nakryikocecaf4a2020-11-09 17:19:32 -0800780 if (info->kernel_btf)
781 printf("name [%s] ", name);
782 else if (name && name[0])
783 printf("name %s ", name);
Andrii Nakryiko71ccb502020-12-01 22:52:41 -0800784 else
785 printf("name <anon> ");
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100786 printf("size %uB", info->btf_size);
787
788 n = 0;
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100789 hashmap__for_each_key_entry(btf_prog_table, entry,
790 u32_as_hash_field(info->id)) {
791 printf("%s%u", n++ == 0 ? " prog_ids " : ",",
792 hash_field_as_u32(entry->value));
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100793 }
794
795 n = 0;
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100796 hashmap__for_each_key_entry(btf_map_table, entry,
797 u32_as_hash_field(info->id)) {
798 printf("%s%u", n++ == 0 ? " map_ids " : ",",
799 hash_field_as_u32(entry->value));
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100800 }
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100801
Quentin Monnetd6699f82021-10-23 21:51:54 +0100802 emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100803
804 printf("\n");
805}
806
807static void
808show_btf_json(struct bpf_btf_info *info, int fd,
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100809 struct hashmap *btf_prog_table,
810 struct hashmap *btf_map_table)
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100811{
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100812 struct hashmap_entry *entry;
Andrii Nakryikocecaf4a2020-11-09 17:19:32 -0800813 const char *name = u64_to_ptr(info->name);
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100814
815 jsonw_start_object(json_wtr); /* btf object */
816 jsonw_uint_field(json_wtr, "id", info->id);
817 jsonw_uint_field(json_wtr, "size", info->btf_size);
818
819 jsonw_name(json_wtr, "prog_ids");
820 jsonw_start_array(json_wtr); /* prog_ids */
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100821 hashmap__for_each_key_entry(btf_prog_table, entry,
822 u32_as_hash_field(info->id)) {
823 jsonw_uint(json_wtr, hash_field_as_u32(entry->value));
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100824 }
825 jsonw_end_array(json_wtr); /* prog_ids */
826
827 jsonw_name(json_wtr, "map_ids");
828 jsonw_start_array(json_wtr); /* map_ids */
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100829 hashmap__for_each_key_entry(btf_map_table, entry,
830 u32_as_hash_field(info->id)) {
831 jsonw_uint(json_wtr, hash_field_as_u32(entry->value));
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100832 }
833 jsonw_end_array(json_wtr); /* map_ids */
Andrii Nakryikod53dee32020-06-19 16:17:02 -0700834
Quentin Monnetd6699f82021-10-23 21:51:54 +0100835 emit_obj_refs_json(refs_table, info->id, json_wtr); /* pids */
Andrii Nakryikod53dee32020-06-19 16:17:02 -0700836
Andrii Nakryikocecaf4a2020-11-09 17:19:32 -0800837 jsonw_bool_field(json_wtr, "kernel", info->kernel_btf);
838
839 if (name && name[0])
840 jsonw_string_field(json_wtr, "name", name);
841
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100842 jsonw_end_object(json_wtr); /* btf object */
843}
844
845static int
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100846show_btf(int fd, struct hashmap *btf_prog_table,
847 struct hashmap *btf_map_table)
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100848{
Andrii Nakryikocecaf4a2020-11-09 17:19:32 -0800849 struct bpf_btf_info info;
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100850 __u32 len = sizeof(info);
Andrii Nakryikocecaf4a2020-11-09 17:19:32 -0800851 char name[64];
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100852 int err;
853
Andrii Nakryikocecaf4a2020-11-09 17:19:32 -0800854 memset(&info, 0, sizeof(info));
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100855 err = bpf_obj_get_info_by_fd(fd, &info, &len);
856 if (err) {
857 p_err("can't get BTF object info: %s", strerror(errno));
858 return -1;
859 }
Andrii Nakryikocecaf4a2020-11-09 17:19:32 -0800860 /* if kernel support emitting BTF object name, pass name pointer */
861 if (info.name_len) {
862 memset(&info, 0, sizeof(info));
863 info.name_len = sizeof(name);
864 info.name = ptr_to_u64(name);
865 len = sizeof(info);
866
867 err = bpf_obj_get_info_by_fd(fd, &info, &len);
868 if (err) {
869 p_err("can't get BTF object info: %s", strerror(errno));
870 return -1;
871 }
872 }
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100873
874 if (json_output)
875 show_btf_json(&info, fd, btf_prog_table, btf_map_table);
876 else
877 show_btf_plain(&info, fd, btf_prog_table, btf_map_table);
878
879 return 0;
880}
881
882static int do_show(int argc, char **argv)
883{
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100884 struct hashmap *btf_prog_table;
885 struct hashmap *btf_map_table;
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100886 int err, fd = -1;
887 __u32 id = 0;
888
889 if (argc == 2) {
890 fd = btf_parse_fd(&argc, &argv);
891 if (fd < 0)
892 return -1;
893 }
894
895 if (argc) {
896 if (fd >= 0)
897 close(fd);
898 return BAD_ARG();
899 }
900
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100901 btf_prog_table = hashmap__new(hash_fn_for_key_as_id,
902 equal_fn_for_key_as_id, NULL);
903 btf_map_table = hashmap__new(hash_fn_for_key_as_id,
904 equal_fn_for_key_as_id, NULL);
905 if (!btf_prog_table || !btf_map_table) {
906 hashmap__free(btf_prog_table);
907 hashmap__free(btf_map_table);
908 if (fd >= 0)
909 close(fd);
910 p_err("failed to create hashmap for object references");
911 return -1;
912 }
913 err = build_btf_tables(btf_prog_table, btf_map_table);
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100914 if (err) {
915 if (fd >= 0)
916 close(fd);
917 return err;
918 }
Andrii Nakryikod53dee32020-06-19 16:17:02 -0700919 build_obj_refs_table(&refs_table, BPF_OBJ_BTF);
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100920
921 if (fd >= 0) {
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100922 err = show_btf(fd, btf_prog_table, btf_map_table);
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100923 close(fd);
924 goto exit_free;
925 }
926
927 if (json_output)
928 jsonw_start_array(json_wtr); /* root array */
929
930 while (true) {
931 err = bpf_btf_get_next_id(id, &id);
932 if (err) {
933 if (errno == ENOENT) {
934 err = 0;
935 break;
936 }
937 p_err("can't get next BTF object: %s%s",
938 strerror(errno),
939 errno == EINVAL ? " -- kernel too old?" : "");
940 err = -1;
941 break;
942 }
943
944 fd = bpf_btf_get_fd_by_id(id);
945 if (fd < 0) {
946 if (errno == ENOENT)
947 continue;
948 p_err("can't get BTF object by id (%u): %s",
949 id, strerror(errno));
950 err = -1;
951 break;
952 }
953
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100954 err = show_btf(fd, btf_prog_table, btf_map_table);
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100955 close(fd);
956 if (err)
957 break;
958 }
959
960 if (json_output)
961 jsonw_end_array(json_wtr); /* root array */
962
963exit_free:
Quentin Monnet2828d0d2021-10-23 21:51:53 +0100964 hashmap__free(btf_prog_table);
965 hashmap__free(btf_map_table);
Quentin Monnetd6699f82021-10-23 21:51:54 +0100966 delete_obj_refs_table(refs_table);
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100967
968 return err;
969}
970
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700971static int do_help(int argc, char **argv)
972{
973 if (json_output) {
974 jsonw_null(json_wtr);
975 return 0;
976 }
977
978 fprintf(stderr,
Quentin Monnet90040352020-05-23 02:07:51 +0100979 "Usage: %1$s %2$s { show | list } [id BTF_ID]\n"
980 " %1$s %2$s dump BTF_SRC [format FORMAT]\n"
981 " %1$s %2$s help\n"
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700982 "\n"
983 " BTF_SRC := { id BTF_ID | prog PROG | map MAP [{key | value | kv | all}] | file FILE }\n"
Andrii Nakryiko2119f212019-05-24 11:59:05 -0700984 " FORMAT := { raw | c }\n"
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700985 " " HELP_SPEC_MAP "\n"
986 " " HELP_SPEC_PROGRAM "\n"
Quentin Monnet8cc8c632021-07-30 22:54:34 +0100987 " " HELP_SPEC_OPTIONS " |\n"
988 " {-B|--base-btf} }\n"
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700989 "",
Quentin Monnet90040352020-05-23 02:07:51 +0100990 bin_name, "btf");
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700991
992 return 0;
993}
994
995static const struct cmd cmds[] = {
Quentin Monnet4d374ba02019-08-20 10:31:54 +0100996 { "show", do_show },
997 { "list", do_show },
Andrii Nakryikoc93cc692019-04-25 15:30:08 -0700998 { "help", do_help },
999 { "dump", do_dump },
1000 { 0 }
1001};
1002
1003int do_btf(int argc, char **argv)
1004{
1005 return cmd_select(cmds, argc, argv, do_help);
1006}