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