xref: /aosp_15_r20/external/bcc/src/cc/bcc_btf.cc (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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, &param);
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, &param);
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, &param);
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 &sections) : 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