293 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2020 Facebook */3#include <stdio.h>4#include <errno.h>5#include <bpf/btf.h>6#include <bpf/libbpf.h>7#include "test_progs.h"8 9static const char * const btf_kind_str_mapping[] = {10 [BTF_KIND_UNKN] = "UNKNOWN",11 [BTF_KIND_INT] = "INT",12 [BTF_KIND_PTR] = "PTR",13 [BTF_KIND_ARRAY] = "ARRAY",14 [BTF_KIND_STRUCT] = "STRUCT",15 [BTF_KIND_UNION] = "UNION",16 [BTF_KIND_ENUM] = "ENUM",17 [BTF_KIND_FWD] = "FWD",18 [BTF_KIND_TYPEDEF] = "TYPEDEF",19 [BTF_KIND_VOLATILE] = "VOLATILE",20 [BTF_KIND_CONST] = "CONST",21 [BTF_KIND_RESTRICT] = "RESTRICT",22 [BTF_KIND_FUNC] = "FUNC",23 [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO",24 [BTF_KIND_VAR] = "VAR",25 [BTF_KIND_DATASEC] = "DATASEC",26 [BTF_KIND_FLOAT] = "FLOAT",27 [BTF_KIND_DECL_TAG] = "DECL_TAG",28 [BTF_KIND_TYPE_TAG] = "TYPE_TAG",29 [BTF_KIND_ENUM64] = "ENUM64",30};31 32static const char *btf_kind_str(__u16 kind)33{34 if (kind > BTF_KIND_ENUM64)35 return "UNKNOWN";36 return btf_kind_str_mapping[kind];37}38 39static const char *btf_int_enc_str(__u8 encoding)40{41 switch (encoding) {42 case 0:43 return "(none)";44 case BTF_INT_SIGNED:45 return "SIGNED";46 case BTF_INT_CHAR:47 return "CHAR";48 case BTF_INT_BOOL:49 return "BOOL";50 default:51 return "UNKN";52 }53}54 55static const char *btf_var_linkage_str(__u32 linkage)56{57 switch (linkage) {58 case BTF_VAR_STATIC:59 return "static";60 case BTF_VAR_GLOBAL_ALLOCATED:61 return "global-alloc";62 default:63 return "(unknown)";64 }65}66 67static const char *btf_func_linkage_str(const struct btf_type *t)68{69 switch (btf_vlen(t)) {70 case BTF_FUNC_STATIC:71 return "static";72 case BTF_FUNC_GLOBAL:73 return "global";74 case BTF_FUNC_EXTERN:75 return "extern";76 default:77 return "(unknown)";78 }79}80 81static const char *btf_str(const struct btf *btf, __u32 off)82{83 if (!off)84 return "(anon)";85 return btf__str_by_offset(btf, off) ?: "(invalid)";86}87 88int fprintf_btf_type_raw(FILE *out, const struct btf *btf, __u32 id)89{90 const struct btf_type *t;91 int kind, i;92 __u32 vlen;93 94 t = btf__type_by_id(btf, id);95 if (!t)96 return -EINVAL;97 98 vlen = btf_vlen(t);99 kind = btf_kind(t);100 101 fprintf(out, "[%u] %s '%s'", id, btf_kind_str(kind), btf_str(btf, t->name_off));102 103 switch (kind) {104 case BTF_KIND_INT:105 fprintf(out, " size=%u bits_offset=%u nr_bits=%u encoding=%s",106 t->size, btf_int_offset(t), btf_int_bits(t),107 btf_int_enc_str(btf_int_encoding(t)));108 break;109 case BTF_KIND_PTR:110 case BTF_KIND_CONST:111 case BTF_KIND_VOLATILE:112 case BTF_KIND_RESTRICT:113 case BTF_KIND_TYPEDEF:114 case BTF_KIND_TYPE_TAG:115 fprintf(out, " type_id=%u", t->type);116 break;117 case BTF_KIND_ARRAY: {118 const struct btf_array *arr = btf_array(t);119 120 fprintf(out, " type_id=%u index_type_id=%u nr_elems=%u",121 arr->type, arr->index_type, arr->nelems);122 break;123 }124 case BTF_KIND_STRUCT:125 case BTF_KIND_UNION: {126 const struct btf_member *m = btf_members(t);127 128 fprintf(out, " size=%u vlen=%u", t->size, vlen);129 for (i = 0; i < vlen; i++, m++) {130 __u32 bit_off, bit_sz;131 132 bit_off = btf_member_bit_offset(t, i);133 bit_sz = btf_member_bitfield_size(t, i);134 fprintf(out, "\n\t'%s' type_id=%u bits_offset=%u",135 btf_str(btf, m->name_off), m->type, bit_off);136 if (bit_sz)137 fprintf(out, " bitfield_size=%u", bit_sz);138 }139 break;140 }141 case BTF_KIND_ENUM: {142 const struct btf_enum *v = btf_enum(t);143 const char *fmt_str;144 145 fmt_str = btf_kflag(t) ? "\n\t'%s' val=%d" : "\n\t'%s' val=%u";146 fprintf(out, " encoding=%s size=%u vlen=%u",147 btf_kflag(t) ? "SIGNED" : "UNSIGNED", t->size, vlen);148 for (i = 0; i < vlen; i++, v++) {149 fprintf(out, fmt_str,150 btf_str(btf, v->name_off), v->val);151 }152 break;153 }154 case BTF_KIND_ENUM64: {155 const struct btf_enum64 *v = btf_enum64(t);156 const char *fmt_str;157 158 fmt_str = btf_kflag(t) ? "\n\t'%s' val=%lld" : "\n\t'%s' val=%llu";159 160 fprintf(out, " encoding=%s size=%u vlen=%u",161 btf_kflag(t) ? "SIGNED" : "UNSIGNED", t->size, vlen);162 for (i = 0; i < vlen; i++, v++) {163 fprintf(out, fmt_str,164 btf_str(btf, v->name_off),165 ((__u64)v->val_hi32 << 32) | v->val_lo32);166 }167 break;168 }169 case BTF_KIND_FWD:170 fprintf(out, " fwd_kind=%s", btf_kflag(t) ? "union" : "struct");171 break;172 case BTF_KIND_FUNC:173 fprintf(out, " type_id=%u linkage=%s", t->type, btf_func_linkage_str(t));174 break;175 case BTF_KIND_FUNC_PROTO: {176 const struct btf_param *p = btf_params(t);177 178 fprintf(out, " ret_type_id=%u vlen=%u", t->type, vlen);179 for (i = 0; i < vlen; i++, p++) {180 fprintf(out, "\n\t'%s' type_id=%u",181 btf_str(btf, p->name_off), p->type);182 }183 break;184 }185 case BTF_KIND_VAR:186 fprintf(out, " type_id=%u, linkage=%s",187 t->type, btf_var_linkage_str(btf_var(t)->linkage));188 break;189 case BTF_KIND_DATASEC: {190 const struct btf_var_secinfo *v = btf_var_secinfos(t);191 192 fprintf(out, " size=%u vlen=%u", t->size, vlen);193 for (i = 0; i < vlen; i++, v++) {194 fprintf(out, "\n\ttype_id=%u offset=%u size=%u",195 v->type, v->offset, v->size);196 }197 break;198 }199 case BTF_KIND_FLOAT:200 fprintf(out, " size=%u", t->size);201 break;202 case BTF_KIND_DECL_TAG:203 fprintf(out, " type_id=%u component_idx=%d",204 t->type, btf_decl_tag(t)->component_idx);205 break;206 default:207 break;208 }209 210 return 0;211}212 213/* Print raw BTF type dump into a local buffer and return string pointer back.214 * Buffer *will* be overwritten by subsequent btf_type_raw_dump() calls215 */216const char *btf_type_raw_dump(const struct btf *btf, int type_id)217{218 static char buf[16 * 1024];219 FILE *buf_file;220 221 buf_file = fmemopen(buf, sizeof(buf) - 1, "w");222 if (!buf_file) {223 fprintf(stderr, "Failed to open memstream: %d\n", errno);224 return NULL;225 }226 227 fprintf_btf_type_raw(buf_file, btf, type_id);228 fflush(buf_file);229 fclose(buf_file);230 231 return buf;232}233 234int btf_validate_raw(struct btf *btf, int nr_types, const char *exp_types[])235{236 int i;237 bool ok = true;238 239 ASSERT_EQ(btf__type_cnt(btf) - 1, nr_types, "btf_nr_types");240 241 for (i = 1; i <= nr_types; i++) {242 if (!ASSERT_STREQ(btf_type_raw_dump(btf, i), exp_types[i - 1], "raw_dump"))243 ok = false;244 }245 246 return ok;247}248 249static void btf_dump_printf(void *ctx, const char *fmt, va_list args)250{251 vfprintf(ctx, fmt, args);252}253 254/* Print BTF-to-C dump into a local buffer and return string pointer back.255 * Buffer *will* be overwritten by subsequent btf_type_raw_dump() calls256 */257const char *btf_type_c_dump(const struct btf *btf)258{259 static char buf[16 * 1024];260 FILE *buf_file;261 struct btf_dump *d = NULL;262 int err, i;263 264 buf_file = fmemopen(buf, sizeof(buf) - 1, "w");265 if (!buf_file) {266 fprintf(stderr, "Failed to open memstream: %d\n", errno);267 return NULL;268 }269 270 d = btf_dump__new(btf, btf_dump_printf, buf_file, NULL);271 if (libbpf_get_error(d)) {272 fprintf(stderr, "Failed to create btf_dump instance: %ld\n", libbpf_get_error(d));273 goto err_out;274 }275 276 for (i = 1; i < btf__type_cnt(btf); i++) {277 err = btf_dump__dump_type(d, i);278 if (err) {279 fprintf(stderr, "Failed to dump type [%d]: %d\n", i, err);280 goto err_out;281 }282 }283 284 btf_dump__free(d);285 fflush(buf_file);286 fclose(buf_file);287 return buf;288err_out:289 btf_dump__free(d);290 fclose(buf_file);291 return NULL;292}293