1 /*
2 * Copyright (c) 2019 Facebook, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "bcc_btf.h"
18 #include <stdarg.h>
19 #include <string.h>
20 #include "linux/btf.h"
21 #include "libbpf.h"
22 #include "bcc_libbpf_inc.h"
23 #include <vector>
24 #include <byteswap.h>
25
26 #define BCC_MAX_ERRNO 4095
27 #define BCC_IS_ERR_VALUE(x) ((x) >= (unsigned long)-BCC_MAX_ERRNO)
28 #define BCC_IS_ERR(ptr) BCC_IS_ERR_VALUE((unsigned long)ptr)
29 #ifndef offsetofend
30 # define offsetofend(TYPE, FIELD) \
31 (offsetof(TYPE, FIELD) + sizeof(((TYPE *)0)->FIELD))
32 #endif
33
34 namespace btf_ext_vendored {
35
36 /* The minimum bpf_func_info checked by the loader */
37 struct bpf_func_info_min {
38 uint32_t insn_off;
39 uint32_t type_id;
40 };
41
42 /* The minimum bpf_line_info checked by the loader */
43 struct bpf_line_info_min {
44 uint32_t insn_off;
45 uint32_t file_name_off;
46 uint32_t line_off;
47 uint32_t line_col;
48 };
49
50 struct btf_ext_sec_setup_param {
51 uint32_t off;
52 uint32_t len;
53 uint32_t min_rec_size;
54 struct btf_ext_info *ext_info;
55 const char *desc;
56 };
57
btf_ext_setup_info(struct btf_ext * btf_ext,struct btf_ext_sec_setup_param * ext_sec)58 static int btf_ext_setup_info(struct btf_ext *btf_ext,
59 struct btf_ext_sec_setup_param *ext_sec)
60 {
61 const struct btf_ext_info_sec *sinfo;
62 struct btf_ext_info *ext_info;
63 uint32_t info_left, record_size;
64 /* The start of the info sec (including the __u32 record_size). */
65 void *info;
66
67 if (ext_sec->len == 0)
68 return 0;
69
70 if (ext_sec->off & 0x03) {
71 /*pr_debug(".BTF.ext %s section is not aligned to 4 bytes\n",
72 ext_sec->desc);*/
73 return -EINVAL;
74 }
75
76 info = (uint8_t*)btf_ext->data + btf_ext->hdr->hdr_len + ext_sec->off;
77 info_left = ext_sec->len;
78
79 if ((uint8_t*)btf_ext->data + btf_ext->data_size < (uint8_t*)info + ext_sec->len) {
80 /*pr_debug("%s section (off:%u len:%u) is beyond the end of the ELF section .BTF.ext\n",
81 ext_sec->desc, ext_sec->off, ext_sec->len);*/
82 return -EINVAL;
83 }
84
85 /* At least a record size */
86 if (info_left < sizeof(uint32_t)) {
87 /*pr_debug(".BTF.ext %s record size not found\n", ext_sec->desc);*/
88 return -EINVAL;
89 }
90
91 /* The record size needs to meet the minimum standard */
92 record_size = *(uint32_t *)info;
93 if (record_size < ext_sec->min_rec_size ||
94 record_size & 0x03) {
95 /*pr_debug("%s section in .BTF.ext has invalid record size %u\n",
96 ext_sec->desc, record_size);*/
97 return -EINVAL;
98 }
99
100 sinfo = (struct btf_ext_info_sec*)((uint8_t*)info + sizeof(uint32_t));
101 info_left -= sizeof(uint32_t);
102
103 /* If no records, return failure now so .BTF.ext won't be used. */
104 if (!info_left) {
105 /*pr_debug("%s section in .BTF.ext has no records", ext_sec->desc);*/
106 return -EINVAL;
107 }
108
109 while (info_left) {
110 unsigned int sec_hdrlen = sizeof(struct btf_ext_info_sec);
111 uint64_t total_record_size;
112 uint32_t num_records;
113
114 if (info_left < sec_hdrlen) {
115 /*pr_debug("%s section header is not found in .BTF.ext\n",
116 ext_sec->desc);*/
117 return -EINVAL;
118 }
119
120 num_records = sinfo->num_info;
121 if (num_records == 0) {
122 /*pr_debug("%s section has incorrect num_records in .BTF.ext\n",
123 ext_sec->desc);*/
124 return -EINVAL;
125 }
126
127 total_record_size = sec_hdrlen +
128 (uint64_t)num_records * record_size;
129 if (info_left < total_record_size) {
130 /*pr_debug("%s section has incorrect num_records in .BTF.ext\n",
131 ext_sec->desc);*/
132 return -EINVAL;
133 }
134
135 info_left -= total_record_size;
136 sinfo = (struct btf_ext_info_sec *)((uint8_t*)sinfo + total_record_size);
137 }
138
139 ext_info = ext_sec->ext_info;
140 ext_info->len = ext_sec->len - sizeof(uint32_t);
141 ext_info->rec_size = record_size;
142 ext_info->info = (uint8_t*)info + sizeof(uint32_t);
143
144 return 0;
145 }
146
btf_ext_setup_func_info(struct btf_ext * btf_ext)147 static int btf_ext_setup_func_info(struct btf_ext *btf_ext)
148 {
149 struct btf_ext_sec_setup_param param = {
150 .off = btf_ext->hdr->func_info_off,
151 .len = btf_ext->hdr->func_info_len,
152 .min_rec_size = sizeof(struct bpf_func_info_min),
153 .ext_info = &btf_ext->func_info,
154 .desc = "func_info"
155 };
156
157 return btf_ext_setup_info(btf_ext, ¶m);
158 }
159
btf_ext_setup_line_info(struct btf_ext * btf_ext)160 static int btf_ext_setup_line_info(struct btf_ext *btf_ext)
161 {
162 struct btf_ext_sec_setup_param param = {
163 .off = btf_ext->hdr->line_info_off,
164 .len = btf_ext->hdr->line_info_len,
165 .min_rec_size = sizeof(struct bpf_line_info_min),
166 .ext_info = &btf_ext->line_info,
167 .desc = "line_info",
168 };
169
170 return btf_ext_setup_info(btf_ext, ¶m);
171 }
172
btf_ext_setup_core_relos(struct btf_ext * btf_ext)173 static int btf_ext_setup_core_relos(struct btf_ext *btf_ext)
174 {
175 struct btf_ext_sec_setup_param param = {
176 .off = btf_ext->hdr->core_relo_off,
177 .len = btf_ext->hdr->core_relo_len,
178 .min_rec_size = sizeof(struct bpf_core_relo),
179 .ext_info = &btf_ext->core_relo_info,
180 .desc = "core_relo",
181 };
182
183 return btf_ext_setup_info(btf_ext, ¶m);
184 }
185
btf_ext_parse_hdr(uint8_t * data,uint32_t data_size)186 static int btf_ext_parse_hdr(uint8_t *data, uint32_t data_size)
187 {
188 const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
189
190 if (data_size < offsetofend(struct btf_ext_header, hdr_len) ||
191 data_size < hdr->hdr_len) {
192 //pr_debug("BTF.ext header not found");
193 return -EINVAL;
194 }
195
196 if (hdr->magic == bswap_16(BTF_MAGIC)) {
197 //pr_warn("BTF.ext in non-native endianness is not supported\n");
198 return -ENOTSUP;
199 } else if (hdr->magic != BTF_MAGIC) {
200 //pr_debug("Invalid BTF.ext magic:%x\n", hdr->magic);
201 return -EINVAL;
202 }
203
204 if (hdr->version != BTF_VERSION) {
205 //pr_debug("Unsupported BTF.ext version:%u\n", hdr->version);
206 return -ENOTSUP;
207 }
208
209 if (hdr->flags) {
210 //pr_debug("Unsupported BTF.ext flags:%x\n", hdr->flags);
211 return -ENOTSUP;
212 }
213
214 if (data_size == hdr->hdr_len) {
215 //pr_debug("BTF.ext has no data\n");
216 return -EINVAL;
217 }
218
219 return 0;
220 }
221
btf_ext__free(struct btf_ext * btf_ext)222 void btf_ext__free(struct btf_ext *btf_ext)
223 {
224 if((!btf_ext) || BCC_IS_ERR_VALUE((unsigned long)btf_ext))
225 return;
226 free(btf_ext->data);
227 free(btf_ext);
228 }
229
btf_ext__new(const uint8_t * data,uint32_t size)230 struct btf_ext *btf_ext__new(const uint8_t *data, uint32_t size)
231 {
232 struct btf_ext *btf_ext;
233 int err;
234
235 btf_ext = (struct btf_ext*)calloc(1, sizeof(struct btf_ext));
236 if (!btf_ext)
237 return (struct btf_ext*)-ENOMEM;
238
239 btf_ext->data_size = size;
240 btf_ext->data = malloc(size);
241 if (!btf_ext->data) {
242 err = -ENOMEM;
243 goto done;
244 }
245 memcpy(btf_ext->data, data, size);
246
247 err = btf_ext_parse_hdr((uint8_t*)btf_ext->data, size);
248 if (err)
249 goto done;
250
251 if (btf_ext->hdr->hdr_len < offsetofend(struct btf_ext_header, line_info_len)) {
252 err = -EINVAL;
253 goto done;
254 }
255
256 err = btf_ext_setup_func_info(btf_ext);
257 if (err)
258 goto done;
259
260 err = btf_ext_setup_line_info(btf_ext);
261 if (err)
262 goto done;
263
264 if (btf_ext->hdr->hdr_len < offsetofend(struct btf_ext_header, core_relo_len)) {
265 err = -EINVAL;
266 goto done;
267 }
268
269 err = btf_ext_setup_core_relos(btf_ext);
270 if (err)
271 goto done;
272
273 done:
274 if (err) {
275 btf_ext__free(btf_ext);
276 return (struct btf_ext*)(uintptr_t)err;
277 }
278
279 return btf_ext;
280 }
281
btf_ext_reloc_info(const struct btf * btf,const struct btf_ext_info * ext_info,const char * sec_name,uint32_t insns_cnt,void ** info,uint32_t * cnt)282 static int btf_ext_reloc_info(const struct btf *btf,
283 const struct btf_ext_info *ext_info,
284 const char *sec_name, uint32_t insns_cnt,
285 void **info, uint32_t *cnt)
286 {
287 uint32_t sec_hdrlen = sizeof(struct btf_ext_info_sec);
288 uint32_t i, record_size, existing_len, records_len;
289 struct btf_ext_info_sec *sinfo;
290 const char *info_sec_name;
291 uint64_t remain_len;
292 void *data;
293
294 record_size = ext_info->rec_size;
295 sinfo = (struct btf_ext_info_sec*)ext_info->info;
296 remain_len = ext_info->len;
297 while (remain_len > 0) {
298 records_len = sinfo->num_info * record_size;
299 info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off);
300 if (strcmp(info_sec_name, sec_name)) {
301 remain_len -= sec_hdrlen + records_len;
302 sinfo = (struct btf_ext_info_sec*)((uint8_t *)sinfo + sec_hdrlen + records_len);
303 continue;
304 }
305
306 existing_len = (*cnt) * record_size;
307 data = realloc(*info, existing_len + records_len);
308 if (!data)
309 return -ENOMEM;
310
311 memcpy((uint8_t*)data + existing_len, sinfo->data, records_len);
312 /* adjust insn_off only, the rest data will be passed
313 * to the kernel.
314 */
315 for (i = 0; i < sinfo->num_info; i++) {
316 uint32_t *insn_off;
317
318 insn_off = (uint32_t *)((uint8_t*)data + existing_len + (i * record_size));
319 *insn_off = *insn_off / sizeof(struct bpf_insn) + insns_cnt;
320 }
321 *info = data;
322 *cnt += sinfo->num_info;
323 return 0;
324 }
325
326 return -ENOENT;
327 }
328
btf_ext__reloc_func_info(const struct btf * btf,const struct btf_ext * btf_ext,const char * sec_name,uint32_t insns_cnt,void ** func_info,uint32_t * cnt)329 int btf_ext__reloc_func_info(const struct btf *btf,
330 const struct btf_ext *btf_ext,
331 const char *sec_name, uint32_t insns_cnt,
332 void **func_info, uint32_t *cnt)
333 {
334 return btf_ext_vendored::btf_ext_reloc_info(btf, &btf_ext->func_info, sec_name,
335 insns_cnt, func_info, cnt);
336 }
337
btf_ext__reloc_line_info(const struct btf * btf,const struct btf_ext * btf_ext,const char * sec_name,uint32_t insns_cnt,void ** line_info,uint32_t * cnt)338 int btf_ext__reloc_line_info(const struct btf *btf,
339 const struct btf_ext *btf_ext,
340 const char *sec_name, uint32_t insns_cnt,
341 void **line_info, uint32_t *cnt)
342 {
343 return btf_ext_vendored::btf_ext_reloc_info(btf, &btf_ext->line_info, sec_name,
344 insns_cnt, line_info, cnt);
345 }
346
347 } // namespace btf_ext_vendored
348
349 namespace ebpf {
350
addString(std::string S)351 int32_t BTFStringTable::addString(std::string S) {
352 // Check whether the string already exists.
353 for (auto &OffsetM : OffsetToIdMap) {
354 if (Table[OffsetM.second] == S)
355 return OffsetM.first;
356 }
357
358 // Make sure we do not overflow the string table.
359 if (OrigTblLen + Size + S.size() + 1 >= BTF_MAX_NAME_OFFSET)
360 return -1;
361
362 // Not find, add to the string table.
363 uint32_t Offset = Size;
364 OffsetToIdMap[Offset] = Table.size();
365 Table.push_back(S);
366 Size += S.size() + 1;
367 return Offset;
368 }
369
BTF(bool debug,sec_map_def & sections)370 BTF::BTF(bool debug, sec_map_def §ions) : debug_(debug),
371 btf_(nullptr), btf_ext_(nullptr), sections_(sections) {
372 if (!debug)
373 libbpf_set_print(NULL);
374 }
375
~BTF()376 BTF::~BTF() {
377 btf__free(btf_);
378 btf_ext__free(btf_ext_);
379 }
380
warning(const char * format,...)381 void BTF::warning(const char *format, ...) {
382 va_list args;
383
384 if (!debug_)
385 return;
386
387 va_start(args, format);
388 vfprintf(stderr, format, args);
389 va_end(args);
390 }
391
fixup_btf(uint8_t * type_sec,uintptr_t type_sec_size,char * strings)392 void BTF::fixup_btf(uint8_t *type_sec, uintptr_t type_sec_size,
393 char *strings) {
394 uint8_t *next_type = type_sec;
395 uint8_t *end_type = type_sec + type_sec_size;
396 int base_size = sizeof(struct btf_type);
397
398 while (next_type < end_type) {
399 struct btf_type *t = (struct btf_type *)next_type;
400 unsigned short vlen = BTF_INFO_VLEN(t->info);
401
402 next_type += base_size;
403
404 switch(BTF_INFO_KIND(t->info)) {
405 case BTF_KIND_FWD:
406 case BTF_KIND_CONST:
407 case BTF_KIND_VOLATILE:
408 case BTF_KIND_RESTRICT:
409 case BTF_KIND_PTR:
410 case BTF_KIND_TYPEDEF:
411 break;
412 case BTF_KIND_FUNC:
413 // sanitize vlen to be 0 since bcc does not
414 // care about func scope (static, global, extern) yet.
415 t->info &= ~0xffff;
416 break;
417 case BTF_KIND_INT:
418 next_type += sizeof(uint32_t);
419 break;
420 case BTF_KIND_ENUM:
421 next_type += vlen * sizeof(struct btf_enum);
422 break;
423 case BTF_KIND_ARRAY:
424 next_type += sizeof(struct btf_array);
425 break;
426 case BTF_KIND_STRUCT:
427 case BTF_KIND_UNION:
428 next_type += vlen * sizeof(struct btf_member);
429 break;
430 case BTF_KIND_FUNC_PROTO:
431 next_type += vlen * sizeof(struct btf_param);
432 break;
433 case BTF_KIND_VAR: {
434 // BTF_KIND_VAR is not used by bcc, so
435 // a sanitization to convert it to an int.
436 // One extra __u32 after btf_type.
437 if (sizeof(struct btf_var) == 4) {
438 t->name_off = 0;
439 t->info = BTF_KIND_INT << 24;
440 t->size = 4;
441
442 unsigned *intp = (unsigned *)next_type;
443 *intp = BTF_INT_BITS(t->size << 3);
444 }
445
446 next_type += sizeof(struct btf_var);
447 break;
448 }
449 case BTF_KIND_DATASEC: {
450 // bcc does not use BTF_KIND_DATASEC, so
451 // a sanitization here to convert it to a list
452 // of void pointers.
453 // btf_var_secinfo is 3 __u32's for each var.
454 if (sizeof(struct btf_var_secinfo) == 12) {
455 t->name_off = 0;
456 t->info = BTF_KIND_PTR << 24;
457 t->type = 0;
458
459 struct btf_type *typep = (struct btf_type *)next_type;
460 for (int i = 0; i < vlen; i++) {
461 typep->name_off = 0;
462 typep->info = BTF_KIND_PTR << 24;
463 typep->type = 0;
464 typep++;
465 }
466 }
467
468 next_type += vlen * sizeof(struct btf_var_secinfo);
469 break;
470 }
471 default:
472 // Something not understood
473 return;
474 }
475 }
476 }
477
478 // The compiler doesn't have source code for remapped files.
479 // So we modify .BTF and .BTF.ext sections here to add these
480 // missing line source codes.
481 // The .BTF and .BTF.ext ELF section specification can be
482 // found at linux repo: linux/Documentation/bpf/btf.rst.
adjust(uint8_t * btf_sec,uintptr_t btf_sec_size,uint8_t * btf_ext_sec,uintptr_t btf_ext_sec_size,std::map<std::string,std::string> & remapped_sources,uint8_t ** new_btf_sec,uintptr_t * new_btf_sec_size)483 void BTF::adjust(uint8_t *btf_sec, uintptr_t btf_sec_size,
484 uint8_t *btf_ext_sec, uintptr_t btf_ext_sec_size,
485 std::map<std::string, std::string> &remapped_sources,
486 uint8_t **new_btf_sec, uintptr_t *new_btf_sec_size) {
487
488 // Line cache for remapped files
489 std::map<std::string, std::vector<std::string>> LineCaches;
490 for (auto it = remapped_sources.begin(); it != remapped_sources.end(); ++it) {
491 size_t FileBufSize = it->second.size();
492 std::vector<std::string> LineCache;
493
494 for (uint32_t start = 0, end = start; end < FileBufSize; end++) {
495 if (it->second[end] == '\n' || end == FileBufSize - 1 ||
496 (it->second[end] == '\r' && it->second[end + 1] == '\n')) {
497 // Not including the endline
498 LineCache.push_back(std::string(it->second.substr(start, end - start)));
499 if (it->second[end] == '\r')
500 end++;
501 start = end + 1;
502 }
503 }
504 LineCaches[it->first] = std::move(LineCache);
505 }
506
507 struct btf_header *hdr = (struct btf_header *)btf_sec;
508 struct btf_ext_vendored::btf_ext_header *ehdr = (struct btf_ext_vendored::btf_ext_header *)btf_ext_sec;
509
510 // Fixup btf for old kernels or kernel requirements.
511 fixup_btf(btf_sec + hdr->hdr_len + hdr->type_off, hdr->type_len,
512 (char *)(btf_sec + hdr->hdr_len + hdr->str_off));
513
514 // Check the LineInfo table and add missing lines
515 char *strings = (char *)(btf_sec + hdr->hdr_len + hdr->str_off);
516 unsigned orig_strings_len = hdr->str_len;
517 unsigned *linfo_s = (unsigned *)(btf_ext_sec + ehdr->hdr_len + ehdr->line_info_off);
518 unsigned lrec_size = *linfo_s;
519 linfo_s++;
520 unsigned linfo_len = ehdr->line_info_len - 4;
521
522 // Go through all line info. For any line number whose line is in the LineCaches,
523 // Correct the line_off and record the corresponding source line in BTFStringTable,
524 // which later will be merged into .BTF string section.
525 BTFStringTable new_strings(orig_strings_len);
526 bool overflow = false;
527 while (!overflow && linfo_len) {
528 unsigned num_recs = linfo_s[1];
529 linfo_s += 2;
530 for (unsigned i = 0; !overflow && i < num_recs; i++) {
531 struct bpf_line_info *linfo = (struct bpf_line_info *)linfo_s;
532 if (linfo->line_off == 0) {
533 for (auto it = LineCaches.begin(); it != LineCaches.end(); ++it) {
534 if (strcmp(strings + linfo->file_name_off, it->first.c_str()) == 0) {
535 unsigned line_num = BPF_LINE_INFO_LINE_NUM(linfo->line_col);
536 if (line_num > 0 && line_num <= it->second.size()) {
537 int offset = new_strings.addString(it->second[line_num - 1]);
538 if (offset < 0) {
539 overflow = true;
540 warning(".BTF string table overflowed, some lines missing\n");
541 break;
542 }
543 linfo->line_off = orig_strings_len + offset;
544 }
545 }
546 }
547 }
548 linfo_s += lrec_size >> 2;
549 }
550 linfo_len -= 8 + num_recs * lrec_size;
551 }
552
553 // If any new source lines need to be recorded, do not touch the original section,
554 // allocate a new section. The original section is allocated through llvm infra.
555 if (new_strings.getSize() > 0) {
556 // LLVM generated .BTF layout always has type_sec followed by str_sec without holes,
557 // so we can just append the new strings to the end and adjust str_sec size.
558 unsigned tmp_sec_size = btf_sec_size + new_strings.getSize();
559 uint8_t *tmp_sec = new uint8_t[tmp_sec_size];
560 memcpy(tmp_sec, btf_sec, btf_sec_size);
561
562 struct btf_header *nhdr = (struct btf_header *)tmp_sec;
563 nhdr->str_len += new_strings.getSize();
564
565 // Populate new strings to the string table.
566 uint8_t *new_str = tmp_sec + nhdr->hdr_len + nhdr->str_off + orig_strings_len;
567 std::vector<std::string> &Table = new_strings.getTable();
568 for (unsigned i = 0; i < Table.size(); i++) {
569 strcpy((char *)new_str, Table[i].c_str());
570 new_str += Table[i].size() + 1;
571 }
572
573 *new_btf_sec = tmp_sec;
574 *new_btf_sec_size = tmp_sec_size;
575 }
576 }
577
load(uint8_t * btf_sec,uintptr_t btf_sec_size,uint8_t * btf_ext_sec,uintptr_t btf_ext_sec_size,std::map<std::string,std::string> & remapped_sources)578 int BTF::load(uint8_t *btf_sec, uintptr_t btf_sec_size,
579 uint8_t *btf_ext_sec, uintptr_t btf_ext_sec_size,
580 std::map<std::string, std::string> &remapped_sources) {
581 struct btf *btf;
582 struct btf_ext_vendored::btf_ext *btf_ext;
583 uint8_t *new_btf_sec = NULL;
584 uintptr_t new_btf_sec_size = 0;
585
586 adjust(btf_sec, btf_sec_size, btf_ext_sec, btf_ext_sec_size,
587 remapped_sources, &new_btf_sec, &new_btf_sec_size);
588
589 if (new_btf_sec) {
590 btf = btf__new(new_btf_sec, new_btf_sec_size);
591 delete[] new_btf_sec;
592 } else {
593 btf = btf__new(btf_sec, btf_sec_size);
594 }
595 if (BCC_IS_ERR(btf)) {
596 warning("Processing .BTF section failed\n");
597 return -1;
598 }
599
600 if (btf__load_into_kernel(btf)) {
601 btf__free(btf);
602 warning("Loading .BTF section failed\n");
603 return -1;
604 }
605
606 btf_ext = btf_ext_vendored::btf_ext__new(btf_ext_sec, btf_ext_sec_size);
607 if (BCC_IS_ERR(btf_ext)) {
608 btf__free(btf);
609 warning("Processing .BTF.ext section failed\n");
610 return -1;
611 }
612
613 btf_ = btf;
614 btf_ext_ = btf_ext;
615 return 0;
616 }
617
get_fd()618 int BTF::get_fd() {
619 return btf__fd(btf_);
620 }
621
get_btf_info(const char * fname,void ** func_info,unsigned * func_info_cnt,unsigned * finfo_rec_size,void ** line_info,unsigned * line_info_cnt,unsigned * linfo_rec_size)622 int BTF::get_btf_info(const char *fname,
623 void **func_info, unsigned *func_info_cnt,
624 unsigned *finfo_rec_size,
625 void **line_info, unsigned *line_info_cnt,
626 unsigned *linfo_rec_size) {
627 int ret;
628
629 *func_info = *line_info = NULL;
630 *func_info_cnt = *line_info_cnt = 0;
631
632 *finfo_rec_size = btf_ext_->func_info.rec_size;
633 *linfo_rec_size = btf_ext_->line_info.rec_size;
634
635 ret = btf_ext_vendored::btf_ext__reloc_func_info(btf_, btf_ext_, fname, 0,
636 func_info, func_info_cnt);
637 if (ret) {
638 warning(".BTF.ext reloc func_info failed\n");
639 return ret;
640 }
641
642 ret = btf_ext_vendored::btf_ext__reloc_line_info(btf_, btf_ext_, fname, 0,
643 line_info, line_info_cnt);
644 if (ret) {
645 warning(".BTF.ext reloc line_info failed\n");
646 return ret;
647 }
648
649 return 0;
650 }
651
get_map_tids(std::string map_name,unsigned expected_ksize,unsigned expected_vsize,unsigned * key_tid,unsigned * value_tid)652 int BTF::get_map_tids(std::string map_name,
653 unsigned expected_ksize, unsigned expected_vsize,
654 unsigned *key_tid, unsigned *value_tid) {
655 auto struct_name = "____btf_map_" + map_name;
656 auto type_id = btf__find_by_name_kind(btf_, struct_name.c_str(), BTF_KIND_STRUCT);
657 if (type_id < 0) {
658 warning("struct %s not found in BTF\n", struct_name.c_str());
659 return -1;
660 }
661
662 auto struct_type = btf__type_by_id(btf_, type_id);
663 if (!struct_type || btf_vlen(struct_type) < 2) {
664 warning("struct %s is not a valid map struct\n", struct_name.c_str());
665 return -1;
666 }
667
668 auto members = btf_members(struct_type);
669 auto key = members[0];
670 auto key_name = btf__name_by_offset(btf_, key.name_off);
671 if (strcmp(key_name, "key")) {
672 warning("'key' should be the first member\n");
673 return -1;
674 }
675 auto key_size = btf__resolve_size(btf_, key.type);
676 if (key_size != expected_ksize) {
677 warning("expect key size to be %d, got %d\n", expected_ksize, key_size);
678 return -1;
679 }
680 *key_tid = key.type;
681
682 auto value = members[1];
683 auto value_name = btf__name_by_offset(btf_, value.name_off);
684 if (strcmp(value_name, "value")) {
685 warning("'value' should be the second member\n");
686 return -1;
687 }
688 auto value_size = btf__resolve_size(btf_, value.type);
689 if (value_size != expected_vsize) {
690 warning("expect value size to be %d, got %d\n", expected_vsize, value_size);
691 return -1;
692 }
693 *value_tid = value.type;
694
695 return 0;
696 }
697
698 } // namespace ebpf
699