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