1use alloc::{
4 borrow::ToOwned,
5 collections::BTreeMap,
6 ffi::CString,
7 string::{String, ToString},
8 vec,
9 vec::Vec,
10};
11use core::{ffi::CStr, mem, ptr, slice::from_raw_parts_mut, str::FromStr};
12
13use log::debug;
14use object::{
15 read::{Object as ElfObject, ObjectSection, Section as ObjSection},
16 Endianness, ObjectSymbol, ObjectSymbolTable, RelocationTarget, SectionIndex, SectionKind,
17 SymbolKind,
18};
19
20#[cfg(not(feature = "std"))]
21use crate::std;
22use crate::{
23 btf::{
24 Array, Btf, BtfError, BtfExt, BtfFeatures, BtfType, DataSecEntry, FuncSecInfo, LineSecInfo,
25 },
26 generated::{
27 bpf_insn, bpf_map_info, bpf_map_type::BPF_MAP_TYPE_ARRAY, BPF_CALL, BPF_F_RDONLY_PROG,
28 BPF_JMP, BPF_K,
29 },
30 maps::{bpf_map_def, BtfMap, BtfMapDef, LegacyMap, Map, PinningType, MINIMUM_MAP_SIZE},
31 programs::{
32 CgroupSockAddrAttachType, CgroupSockAttachType, CgroupSockoptAttachType, XdpAttachType,
33 },
34 relocation::*,
35 util::HashMap,
36};
37
38const KERNEL_VERSION_ANY: u32 = 0xFFFF_FFFE;
39
40#[derive(Default, Debug)]
42#[allow(missing_docs)]
43pub struct Features {
44 bpf_name: bool,
45 bpf_probe_read_kernel: bool,
46 bpf_perf_link: bool,
47 bpf_global_data: bool,
48 bpf_cookie: bool,
49 cpumap_prog_id: bool,
50 devmap_prog_id: bool,
51 prog_info_map_ids: bool,
52 prog_info_gpl_compatible: bool,
53 btf: Option<BtfFeatures>,
54}
55
56impl Features {
57 #[doc(hidden)]
58 #[allow(clippy::too_many_arguments)]
59 pub fn new(
60 bpf_name: bool,
61 bpf_probe_read_kernel: bool,
62 bpf_perf_link: bool,
63 bpf_global_data: bool,
64 bpf_cookie: bool,
65 cpumap_prog_id: bool,
66 devmap_prog_id: bool,
67 prog_info_map_ids: bool,
68 prog_info_gpl_compatible: bool,
69 btf: Option<BtfFeatures>,
70 ) -> Self {
71 Self {
72 bpf_name,
73 bpf_probe_read_kernel,
74 bpf_perf_link,
75 bpf_global_data,
76 bpf_cookie,
77 cpumap_prog_id,
78 devmap_prog_id,
79 prog_info_map_ids,
80 prog_info_gpl_compatible,
81 btf,
82 }
83 }
84
85 pub fn bpf_name(&self) -> bool {
90 self.bpf_name
91 }
92
93 pub fn bpf_probe_read_kernel(&self) -> bool {
95 self.bpf_probe_read_kernel
96 }
97
98 pub fn bpf_perf_link(&self) -> bool {
100 self.bpf_perf_link
101 }
102
103 pub fn bpf_global_data(&self) -> bool {
105 self.bpf_global_data
106 }
107
108 pub fn bpf_cookie(&self) -> bool {
110 self.bpf_cookie
111 }
112
113 pub fn cpumap_prog_id(&self) -> bool {
115 self.cpumap_prog_id
116 }
117
118 pub fn devmap_prog_id(&self) -> bool {
120 self.devmap_prog_id
121 }
122
123 pub fn prog_info_map_ids(&self) -> bool {
125 self.prog_info_map_ids
126 }
127
128 pub fn prog_info_gpl_compatible(&self) -> bool {
130 self.prog_info_gpl_compatible
131 }
132
133 pub fn btf(&self) -> Option<&BtfFeatures> {
135 self.btf.as_ref()
136 }
137}
138
139#[derive(Clone, Debug)]
141pub struct Object {
142 pub endianness: Endianness,
144 pub license: CString,
146 pub kernel_version: Option<u32>,
148 pub btf: Option<Btf>,
150 pub btf_ext: Option<BtfExt>,
152 pub maps: HashMap<String, Map>,
154 pub programs: HashMap<String, Program>,
157 pub functions: BTreeMap<(usize, u64), Function>,
159 pub(crate) relocations: HashMap<SectionIndex, HashMap<u64, Relocation>>,
160 pub(crate) symbol_table: HashMap<usize, Symbol>,
161 pub(crate) symbols_by_section: HashMap<SectionIndex, Vec<usize>>,
162 pub(crate) section_infos: HashMap<String, (SectionIndex, u64)>,
163 pub(crate) symbol_offset_by_name: HashMap<String, u64>,
166}
167
168#[derive(Debug, Clone)]
170pub struct Program {
171 pub license: CString,
173 pub kernel_version: Option<u32>,
175 pub section: ProgramSection,
177 pub section_index: usize,
179 pub address: u64,
181}
182
183impl Program {
184 pub fn function_key(&self) -> (usize, u64) {
186 (self.section_index, self.address)
187 }
188}
189
190#[derive(Debug, Clone)]
192pub struct Function {
193 pub address: u64,
195 pub name: String,
197 pub section_index: SectionIndex,
199 pub section_offset: usize,
201 pub instructions: Vec<bpf_insn>,
203 pub func_info: FuncSecInfo,
205 pub line_info: LineSecInfo,
207 pub func_info_rec_size: usize,
209 pub line_info_rec_size: usize,
211}
212
213#[derive(Debug, Clone)]
243#[allow(missing_docs)]
244pub enum ProgramSection {
245 KRetProbe,
246 KProbe,
247 UProbe {
248 sleepable: bool,
249 },
250 URetProbe {
251 sleepable: bool,
252 },
253 TracePoint,
254 SocketFilter,
255 Xdp {
256 frags: bool,
257 attach_type: XdpAttachType,
258 },
259 SkMsg,
260 SkSkbStreamParser,
261 SkSkbStreamVerdict,
262 SockOps,
263 SchedClassifier,
264 CgroupSkb,
265 CgroupSkbIngress,
266 CgroupSkbEgress,
267 CgroupSockAddr {
268 attach_type: CgroupSockAddrAttachType,
269 },
270 CgroupSysctl,
271 CgroupSockopt {
272 attach_type: CgroupSockoptAttachType,
273 },
274 LircMode2,
275 PerfEvent,
276 RawTracePoint,
277 Lsm {
278 sleepable: bool,
279 },
280 BtfTracePoint,
281 FEntry {
282 sleepable: bool,
283 },
284 FExit {
285 sleepable: bool,
286 },
287 Extension,
288 SkLookup,
289 CgroupSock {
290 attach_type: CgroupSockAttachType,
291 },
292 CgroupDevice,
293}
294
295impl FromStr for ProgramSection {
296 type Err = ParseError;
297
298 fn from_str(section: &str) -> Result<ProgramSection, ParseError> {
299 use ProgramSection::*;
300
301 let mut pieces = section.split('/');
304 let mut next = || {
305 pieces
306 .next()
307 .ok_or_else(|| ParseError::InvalidProgramSection {
308 section: section.to_owned(),
309 })
310 };
311 let kind = next()?;
312
313 Ok(match kind {
314 "kprobe" => KProbe,
315 "kretprobe" => KRetProbe,
316 "uprobe" => UProbe { sleepable: false },
317 "uprobe.s" => UProbe { sleepable: true },
318 "uretprobe" => URetProbe { sleepable: false },
319 "uretprobe.s" => URetProbe { sleepable: true },
320 "xdp" | "xdp.frags" => Xdp {
321 frags: kind == "xdp.frags",
322 attach_type: match pieces.next() {
323 None => XdpAttachType::Interface,
324 Some("cpumap") => XdpAttachType::CpuMap,
325 Some("devmap") => XdpAttachType::DevMap,
326 Some(_) => {
327 return Err(ParseError::InvalidProgramSection {
328 section: section.to_owned(),
329 })
330 }
331 },
332 },
333 "tp_btf" => BtfTracePoint,
334 "tracepoint" | "tp" => TracePoint,
335 "socket" => SocketFilter,
336 "sk_msg" => SkMsg,
337 "sk_skb" => {
338 let name = next()?;
339 match name {
340 "stream_parser" => SkSkbStreamParser,
341 "stream_verdict" => SkSkbStreamVerdict,
342 _ => {
343 return Err(ParseError::InvalidProgramSection {
344 section: section.to_owned(),
345 })
346 }
347 }
348 }
349 "sockops" => SockOps,
350 "classifier" => SchedClassifier,
351 "cgroup_skb" => {
352 let name = next()?;
353 match name {
354 "ingress" => CgroupSkbIngress,
355 "egress" => CgroupSkbEgress,
356 _ => {
357 return Err(ParseError::InvalidProgramSection {
358 section: section.to_owned(),
359 })
360 }
361 }
362 }
363 "cgroup" => {
364 let name = next()?;
365 match name {
366 "skb" => CgroupSkb,
367 "sysctl" => CgroupSysctl,
368 "dev" => CgroupDevice,
369 "getsockopt" => CgroupSockopt {
370 attach_type: CgroupSockoptAttachType::Get,
371 },
372 "setsockopt" => CgroupSockopt {
373 attach_type: CgroupSockoptAttachType::Set,
374 },
375 "sock" => CgroupSock {
376 attach_type: CgroupSockAttachType::default(),
377 },
378 "post_bind4" => CgroupSock {
379 attach_type: CgroupSockAttachType::PostBind4,
380 },
381 "post_bind6" => CgroupSock {
382 attach_type: CgroupSockAttachType::PostBind6,
383 },
384 "sock_create" => CgroupSock {
385 attach_type: CgroupSockAttachType::SockCreate,
386 },
387 "sock_release" => CgroupSock {
388 attach_type: CgroupSockAttachType::SockRelease,
389 },
390 "bind4" => CgroupSockAddr {
391 attach_type: CgroupSockAddrAttachType::Bind4,
392 },
393 "bind6" => CgroupSockAddr {
394 attach_type: CgroupSockAddrAttachType::Bind6,
395 },
396 "connect4" => CgroupSockAddr {
397 attach_type: CgroupSockAddrAttachType::Connect4,
398 },
399 "connect6" => CgroupSockAddr {
400 attach_type: CgroupSockAddrAttachType::Connect6,
401 },
402 "getpeername4" => CgroupSockAddr {
403 attach_type: CgroupSockAddrAttachType::GetPeerName4,
404 },
405 "getpeername6" => CgroupSockAddr {
406 attach_type: CgroupSockAddrAttachType::GetPeerName6,
407 },
408 "getsockname4" => CgroupSockAddr {
409 attach_type: CgroupSockAddrAttachType::GetSockName4,
410 },
411 "getsockname6" => CgroupSockAddr {
412 attach_type: CgroupSockAddrAttachType::GetSockName6,
413 },
414 "sendmsg4" => CgroupSockAddr {
415 attach_type: CgroupSockAddrAttachType::UDPSendMsg4,
416 },
417 "sendmsg6" => CgroupSockAddr {
418 attach_type: CgroupSockAddrAttachType::UDPSendMsg6,
419 },
420 "recvmsg4" => CgroupSockAddr {
421 attach_type: CgroupSockAddrAttachType::UDPRecvMsg4,
422 },
423 "recvmsg6" => CgroupSockAddr {
424 attach_type: CgroupSockAddrAttachType::UDPRecvMsg6,
425 },
426 _ => {
427 return Err(ParseError::InvalidProgramSection {
428 section: section.to_owned(),
429 });
430 }
431 }
432 }
433 "lirc_mode2" => LircMode2,
434 "perf_event" => PerfEvent,
435 "raw_tp" | "raw_tracepoint" => RawTracePoint,
436 "lsm" => Lsm { sleepable: false },
437 "lsm.s" => Lsm { sleepable: true },
438 "fentry" => FEntry { sleepable: false },
439 "fentry.s" => FEntry { sleepable: true },
440 "fexit" => FExit { sleepable: false },
441 "fexit.s" => FExit { sleepable: true },
442 "freplace" => Extension,
443 "sk_lookup" => SkLookup,
444 _ => {
445 return Err(ParseError::InvalidProgramSection {
446 section: section.to_owned(),
447 })
448 }
449 })
450 }
451}
452
453impl Object {
454 pub fn parse(data: &[u8]) -> Result<Object, ParseError> {
456 let obj = object::read::File::parse(data).map_err(ParseError::ElfError)?;
457 let endianness = obj.endianness();
458
459 let license = if let Some(section) = obj.section_by_name("license") {
460 parse_license(Section::try_from(§ion)?.data)?
461 } else {
462 CString::new("GPL").unwrap()
463 };
464
465 let kernel_version = if let Some(section) = obj.section_by_name("version") {
466 parse_version(Section::try_from(§ion)?.data, endianness)?
467 } else {
468 None
469 };
470
471 let mut bpf_obj = Object::new(endianness, license, kernel_version);
472
473 if let Some(symbol_table) = obj.symbol_table() {
474 for symbol in symbol_table.symbols() {
475 let name = symbol
476 .name()
477 .ok()
478 .map(String::from)
479 .ok_or(BtfError::InvalidSymbolName)?;
480 let sym = Symbol {
481 index: symbol.index().0,
482 name: Some(name.clone()),
483 section_index: symbol.section().index().map(|i| i.0),
484 address: symbol.address(),
485 size: symbol.size(),
486 is_definition: symbol.is_definition(),
487 kind: symbol.kind(),
488 };
489 bpf_obj.symbol_table.insert(symbol.index().0, sym);
490 if let Some(section_idx) = symbol.section().index() {
491 bpf_obj
492 .symbols_by_section
493 .entry(section_idx)
494 .or_default()
495 .push(symbol.index().0);
496 }
497 if symbol.is_global() || symbol.kind() == SymbolKind::Data {
498 bpf_obj.symbol_offset_by_name.insert(name, symbol.address());
499 }
500 }
501 }
502
503 if let Some(s) = obj.section_by_name(".BTF") {
507 bpf_obj.parse_section(Section::try_from(&s)?)?;
508 if let Some(s) = obj.section_by_name(".BTF.ext") {
509 bpf_obj.parse_section(Section::try_from(&s)?)?;
510 }
511 }
512
513 for s in obj.sections() {
514 if let Ok(name) = s.name() {
515 if name == ".BTF" || name == ".BTF.ext" {
516 continue;
517 }
518 }
519
520 bpf_obj.parse_section(Section::try_from(&s)?)?;
521 }
522
523 Ok(bpf_obj)
524 }
525
526 fn new(endianness: Endianness, license: CString, kernel_version: Option<u32>) -> Object {
527 Object {
528 endianness,
529 license,
530 kernel_version,
531 btf: None,
532 btf_ext: None,
533 maps: HashMap::new(),
534 programs: HashMap::new(),
535 functions: BTreeMap::new(),
536 relocations: HashMap::new(),
537 symbol_table: HashMap::new(),
538 symbols_by_section: HashMap::new(),
539 section_infos: HashMap::new(),
540 symbol_offset_by_name: HashMap::new(),
541 }
542 }
543
544 pub fn patch_map_data(
546 &mut self,
547 globals: HashMap<&str, (&[u8], bool)>,
548 ) -> Result<(), ParseError> {
549 let symbols: HashMap<String, &Symbol> = self
550 .symbol_table
551 .iter()
552 .filter(|(_, s)| s.name.is_some())
553 .map(|(_, s)| (s.name.as_ref().unwrap().clone(), s))
554 .collect();
555
556 for (name, (data, must_exist)) in globals {
557 if let Some(symbol) = symbols.get(name) {
558 if data.len() as u64 != symbol.size {
559 return Err(ParseError::InvalidGlobalData {
560 name: name.to_string(),
561 sym_size: symbol.size,
562 data_size: data.len(),
563 });
564 }
565 let (_, map) = self
566 .maps
567 .iter_mut()
568 .find(|(_, m)| symbol.section_index == Some(m.section_index()))
571 .ok_or_else(|| ParseError::MapNotFound {
572 index: symbol.section_index.unwrap_or(0),
573 })?;
574 let start = symbol.address as usize;
575 let end = start + symbol.size as usize;
576 if start > end || end > map.data().len() {
577 return Err(ParseError::InvalidGlobalData {
578 name: name.to_string(),
579 sym_size: symbol.size,
580 data_size: data.len(),
581 });
582 }
583 map.data_mut().splice(start..end, data.iter().cloned());
584 } else if must_exist {
585 return Err(ParseError::SymbolNotFound {
586 name: name.to_owned(),
587 });
588 }
589 }
590 Ok(())
591 }
592
593 fn parse_btf(&mut self, section: &Section) -> Result<(), BtfError> {
594 self.btf = Some(Btf::parse(section.data, self.endianness)?);
595
596 Ok(())
597 }
598
599 fn parse_btf_ext(&mut self, section: &Section) -> Result<(), BtfError> {
600 self.btf_ext = Some(BtfExt::parse(
601 section.data,
602 self.endianness,
603 self.btf.as_ref().unwrap(),
604 )?);
605 Ok(())
606 }
607
608 fn parse_programs(&mut self, section: &Section) -> Result<(), ParseError> {
609 let program_section = ProgramSection::from_str(section.name)?;
610 let syms =
611 self.symbols_by_section
612 .get(§ion.index)
613 .ok_or(ParseError::NoSymbolsForSection {
614 section_name: section.name.to_string(),
615 })?;
616 for symbol_index in syms {
617 let symbol = self
618 .symbol_table
619 .get(symbol_index)
620 .expect("all symbols in symbols_by_section are also in symbol_table");
621
622 let name = match (symbol.name.as_ref(), symbol.kind) {
624 (Some(name), SymbolKind::Text) if !name.is_empty() => name,
625 _ => continue,
626 };
627
628 let (p, f) =
629 self.parse_program(section, program_section.clone(), name.to_string(), symbol)?;
630 let key = p.function_key();
631 self.programs.insert(f.name.clone(), p);
632 self.functions.insert(key, f);
633 }
634 Ok(())
635 }
636
637 fn parse_program(
638 &self,
639 section: &Section,
640 program_section: ProgramSection,
641 name: String,
642 symbol: &Symbol,
643 ) -> Result<(Program, Function), ParseError> {
644 let offset = symbol.address as usize - section.address as usize;
645 let (func_info, line_info, func_info_rec_size, line_info_rec_size) =
646 get_func_and_line_info(self.btf_ext.as_ref(), symbol, section, offset, true);
647
648 let start = symbol.address as usize;
649 let end = (symbol.address + symbol.size) as usize;
650
651 let function = Function {
652 name: name.to_owned(),
653 address: symbol.address,
654 section_index: section.index,
655 section_offset: start,
656 instructions: copy_instructions(§ion.data[start..end])?,
657 func_info,
658 line_info,
659 func_info_rec_size,
660 line_info_rec_size,
661 };
662
663 Ok((
664 Program {
665 license: self.license.clone(),
666 kernel_version: self.kernel_version,
667 section: program_section.clone(),
668 section_index: section.index.0,
669 address: symbol.address,
670 },
671 function,
672 ))
673 }
674
675 fn parse_text_section(&mut self, section: Section) -> Result<(), ParseError> {
676 let mut symbols_by_address = HashMap::new();
677
678 for sym in self.symbol_table.values() {
679 if sym.is_definition
680 && sym.kind == SymbolKind::Text
681 && sym.section_index == Some(section.index.0)
682 {
683 if symbols_by_address.contains_key(&sym.address) {
684 return Err(ParseError::SymbolTableConflict {
685 section_index: section.index.0,
686 address: sym.address,
687 });
688 }
689 symbols_by_address.insert(sym.address, sym);
690 }
691 }
692
693 let mut offset = 0;
694 while offset < section.data.len() {
695 let address = section.address + offset as u64;
696 let sym = symbols_by_address
697 .get(&address)
698 .ok_or(ParseError::UnknownSymbol {
699 section_index: section.index.0,
700 address,
701 })?;
702 if sym.size == 0 {
703 return Err(ParseError::InvalidSymbol {
704 index: sym.index,
705 name: sym.name.clone(),
706 });
707 }
708
709 let (func_info, line_info, func_info_rec_size, line_info_rec_size) =
710 get_func_and_line_info(self.btf_ext.as_ref(), sym, §ion, offset, false);
711
712 self.functions.insert(
713 (section.index.0, sym.address),
714 Function {
715 address,
716 name: sym.name.clone().unwrap(),
717 section_index: section.index,
718 section_offset: offset,
719 instructions: copy_instructions(
720 §ion.data[offset..offset + sym.size as usize],
721 )?,
722 func_info,
723 line_info,
724 func_info_rec_size,
725 line_info_rec_size,
726 },
727 );
728
729 offset += sym.size as usize;
730 }
731
732 if !section.relocations.is_empty() {
733 self.relocations.insert(
734 section.index,
735 section
736 .relocations
737 .into_iter()
738 .map(|rel| (rel.offset, rel))
739 .collect(),
740 );
741 }
742
743 Ok(())
744 }
745
746 fn parse_btf_maps(&mut self, section: &Section) -> Result<(), ParseError> {
747 if self.btf.is_none() {
748 return Err(ParseError::NoBTF);
749 }
750 let btf = self.btf.as_ref().unwrap();
751 let maps: HashMap<&String, usize> = self
752 .symbols_by_section
753 .get(§ion.index)
754 .ok_or(ParseError::NoSymbolsForSection {
755 section_name: section.name.to_owned(),
756 })?
757 .iter()
758 .filter_map(|s| {
759 let symbol = self.symbol_table.get(s).unwrap();
760 symbol.name.as_ref().map(|name| (name, symbol.index))
761 })
762 .collect();
763
764 for t in btf.types() {
765 if let BtfType::DataSec(datasec) = &t {
766 let type_name = match btf.type_name(t) {
767 Ok(name) => name,
768 _ => continue,
769 };
770 if type_name == section.name {
771 for info in &datasec.entries {
773 let (map_name, def) = parse_btf_map_def(btf, info)?;
774 let symbol_index =
775 maps.get(&map_name)
776 .ok_or_else(|| ParseError::SymbolNotFound {
777 name: map_name.to_string(),
778 })?;
779 self.maps.insert(
780 map_name,
781 Map::Btf(BtfMap {
782 def,
783 section_index: section.index.0,
784 symbol_index: *symbol_index,
785 data: Vec::new(),
786 }),
787 );
788 }
789 }
790 }
791 }
792 Ok(())
793 }
794
795 fn parse_maps_section<'a, I: Iterator<Item = &'a usize>>(
799 &self,
800 maps: &mut HashMap<String, Map>,
801 section: &Section,
802 symbols: I,
803 ) -> Result<(), ParseError> {
804 let mut have_symbols = false;
805 for i in symbols {
807 let sym = self.symbol_table.get(i).ok_or(ParseError::SymbolNotFound {
808 name: i.to_string(),
809 })?;
810 let start = sym.address as usize;
811 let end = start + sym.size as usize;
812 let data = §ion.data[start..end];
813 let name = sym
814 .name
815 .as_ref()
816 .ok_or(ParseError::MapSymbolNameNotFound { i: *i })?;
817 let def = parse_map_def(name, data)?;
818 maps.insert(
819 name.to_string(),
820 Map::Legacy(LegacyMap {
821 section_index: section.index.0,
822 section_kind: section.kind,
823 symbol_index: Some(sym.index),
824 def,
825 data: Vec::new(),
826 }),
827 );
828 have_symbols = true;
829 }
830 if !have_symbols {
831 return Err(ParseError::NoSymbolsForSection {
832 section_name: section.name.to_owned(),
833 });
834 }
835
836 Ok(())
837 }
838
839 fn parse_section(&mut self, section: Section) -> Result<(), ParseError> {
840 self.section_infos
841 .insert(section.name.to_owned(), (section.index, section.size));
842 match section.kind {
843 EbpfSectionKind::Data | EbpfSectionKind::Rodata | EbpfSectionKind::Bss => {
844 self.maps
845 .insert(section.name.to_string(), parse_data_map_section(§ion)?);
846 }
847 EbpfSectionKind::Text => self.parse_text_section(section)?,
848 EbpfSectionKind::Btf => self.parse_btf(§ion)?,
849 EbpfSectionKind::BtfExt => self.parse_btf_ext(§ion)?,
850 EbpfSectionKind::BtfMaps => self.parse_btf_maps(§ion)?,
851 EbpfSectionKind::Maps => {
852 let mut maps = mem::take(&mut self.maps);
855
856 let symbols = self
859 .symbols_by_section
860 .get(§ion.index)
861 .ok_or(ParseError::NoSymbolsForSection {
862 section_name: section.name.to_owned(),
863 })?
864 .iter();
865
866 let res = self.parse_maps_section(&mut maps, §ion, symbols);
867
868 self.maps = maps;
870
871 res?
872 }
873 EbpfSectionKind::Program => {
874 self.parse_programs(§ion)?;
875 if !section.relocations.is_empty() {
876 self.relocations.insert(
877 section.index,
878 section
879 .relocations
880 .into_iter()
881 .map(|rel| (rel.offset, rel))
882 .collect(),
883 );
884 }
885 }
886 EbpfSectionKind::Undefined | EbpfSectionKind::License | EbpfSectionKind::Version => {}
887 }
888
889 Ok(())
890 }
891
892 pub fn sanitize_functions(&mut self, features: &Features) {
894 for function in self.functions.values_mut() {
895 function.sanitize(features);
896 }
897 }
898}
899
900fn insn_is_helper_call(ins: &bpf_insn) -> bool {
901 let klass = (ins.code & 0x07) as u32;
902 let op = (ins.code & 0xF0) as u32;
903 let src = (ins.code & 0x08) as u32;
904
905 klass == BPF_JMP && op == BPF_CALL && src == BPF_K && ins.src_reg() == 0 && ins.dst_reg() == 0
906}
907
908const BPF_FUNC_PROBE_READ: i32 = 4;
909const BPF_FUNC_PROBE_READ_STR: i32 = 45;
910const BPF_FUNC_PROBE_READ_USER: i32 = 112;
911const BPF_FUNC_PROBE_READ_KERNEL: i32 = 113;
912const BPF_FUNC_PROBE_READ_USER_STR: i32 = 114;
913const BPF_FUNC_PROBE_READ_KERNEL_STR: i32 = 115;
914
915impl Function {
916 fn sanitize(&mut self, features: &Features) {
917 for inst in &mut self.instructions {
918 if !insn_is_helper_call(inst) {
919 continue;
920 }
921
922 match inst.imm {
923 BPF_FUNC_PROBE_READ_USER | BPF_FUNC_PROBE_READ_KERNEL
924 if !features.bpf_probe_read_kernel =>
925 {
926 inst.imm = BPF_FUNC_PROBE_READ;
927 }
928 BPF_FUNC_PROBE_READ_USER_STR | BPF_FUNC_PROBE_READ_KERNEL_STR
929 if !features.bpf_probe_read_kernel =>
930 {
931 inst.imm = BPF_FUNC_PROBE_READ_STR;
932 }
933 _ => {}
934 }
935 }
936 }
937}
938
939#[derive(Debug, thiserror::Error)]
941#[allow(missing_docs)]
942pub enum ParseError {
943 #[error("error parsing ELF data")]
944 ElfError(object::read::Error),
945
946 #[error("BTF error")]
948 BtfError(#[from] BtfError),
949
950 #[error("invalid license `{data:?}`: missing NULL terminator")]
951 MissingLicenseNullTerminator { data: Vec<u8> },
952
953 #[error("invalid license `{data:?}`")]
954 InvalidLicense { data: Vec<u8> },
955
956 #[error("invalid kernel version `{data:?}`")]
957 InvalidKernelVersion { data: Vec<u8> },
958
959 #[error("error parsing section with index {index}")]
960 SectionError {
961 index: usize,
962 error: object::read::Error,
963 },
964
965 #[error("unsupported relocation target")]
966 UnsupportedRelocationTarget,
967
968 #[error("invalid program section `{section}`")]
969 InvalidProgramSection { section: String },
970
971 #[error("invalid program code")]
972 InvalidProgramCode,
973
974 #[error("error parsing map `{name}`")]
975 InvalidMapDefinition { name: String },
976
977 #[error("two or more symbols in section `{section_index}` have the same address {address:#X}")]
978 SymbolTableConflict { section_index: usize, address: u64 },
979
980 #[error("unknown symbol in section `{section_index}` at address {address:#X}")]
981 UnknownSymbol { section_index: usize, address: u64 },
982
983 #[error("invalid symbol, index `{index}` name: {}", .name.as_ref().unwrap_or(&"[unknown]".into()))]
984 InvalidSymbol { index: usize, name: Option<String> },
985
986 #[error("symbol {name} has size `{sym_size}`, but provided data is of size `{data_size}`")]
987 InvalidGlobalData {
988 name: String,
989 sym_size: u64,
990 data_size: usize,
991 },
992
993 #[error("symbol with name {name} not found in the symbols table")]
994 SymbolNotFound { name: String },
995
996 #[error("map for section with index {index} not found")]
997 MapNotFound { index: usize },
998
999 #[error("the map number {i} in the `maps` section doesn't have a symbol name")]
1000 MapSymbolNameNotFound { i: usize },
1001
1002 #[error("no symbols found in the {section_name} section")]
1003 NoSymbolsForSection { section_name: String },
1004
1005 #[error("no BTF parsed for object")]
1007 NoBTF,
1008}
1009
1010pub struct InvalidTypeBinding<T> {
1012 pub value: T,
1014}
1015
1016#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1018pub enum EbpfSectionKind {
1019 Undefined,
1021 Maps,
1023 BtfMaps,
1025 Program,
1027 Data,
1029 Rodata,
1031 Bss,
1033 Text,
1035 Btf,
1037 BtfExt,
1039 License,
1041 Version,
1043}
1044
1045impl EbpfSectionKind {
1046 fn from_name(name: &str) -> EbpfSectionKind {
1047 if name.starts_with("license") {
1048 EbpfSectionKind::License
1049 } else if name.starts_with("version") {
1050 EbpfSectionKind::Version
1051 } else if name.starts_with("maps") {
1052 EbpfSectionKind::Maps
1053 } else if name.starts_with(".maps") {
1054 EbpfSectionKind::BtfMaps
1055 } else if name.starts_with(".text") {
1056 EbpfSectionKind::Text
1057 } else if name.starts_with(".bss") {
1058 EbpfSectionKind::Bss
1059 } else if name.starts_with(".data") {
1060 EbpfSectionKind::Data
1061 } else if name.starts_with(".rodata") {
1062 EbpfSectionKind::Rodata
1063 } else if name == ".BTF" {
1064 EbpfSectionKind::Btf
1065 } else if name == ".BTF.ext" {
1066 EbpfSectionKind::BtfExt
1067 } else {
1068 EbpfSectionKind::Undefined
1069 }
1070 }
1071}
1072
1073#[derive(Debug)]
1074struct Section<'a> {
1075 index: SectionIndex,
1076 kind: EbpfSectionKind,
1077 address: u64,
1078 name: &'a str,
1079 data: &'a [u8],
1080 size: u64,
1081 relocations: Vec<Relocation>,
1082}
1083
1084impl<'a> TryFrom<&'a ObjSection<'_, '_>> for Section<'a> {
1085 type Error = ParseError;
1086
1087 fn try_from(section: &'a ObjSection) -> Result<Section<'a>, ParseError> {
1088 let index = section.index();
1089 let map_err = |error| ParseError::SectionError {
1090 index: index.0,
1091 error,
1092 };
1093 let name = section.name().map_err(map_err)?;
1094 let kind = match EbpfSectionKind::from_name(name) {
1095 EbpfSectionKind::Undefined => {
1096 if section.kind() == SectionKind::Text && section.size() > 0 {
1097 EbpfSectionKind::Program
1098 } else {
1099 EbpfSectionKind::Undefined
1100 }
1101 }
1102 k => k,
1103 };
1104 Ok(Section {
1105 index,
1106 kind,
1107 address: section.address(),
1108 name,
1109 data: section.data().map_err(map_err)?,
1110 size: section.size(),
1111 relocations: section
1112 .relocations()
1113 .map(|(offset, r)| {
1114 Ok(Relocation {
1115 symbol_index: match r.target() {
1116 RelocationTarget::Symbol(index) => index.0,
1117 _ => return Err(ParseError::UnsupportedRelocationTarget),
1118 },
1119 offset,
1120 size: r.size(),
1121 })
1122 })
1123 .collect::<Result<Vec<_>, _>>()?,
1124 })
1125 }
1126}
1127
1128fn parse_license(data: &[u8]) -> Result<CString, ParseError> {
1129 if data.len() < 2 {
1130 return Err(ParseError::InvalidLicense {
1131 data: data.to_vec(),
1132 });
1133 }
1134 if data[data.len() - 1] != 0 {
1135 return Err(ParseError::MissingLicenseNullTerminator {
1136 data: data.to_vec(),
1137 });
1138 }
1139
1140 Ok(CStr::from_bytes_with_nul(data)
1141 .map_err(|_| ParseError::InvalidLicense {
1142 data: data.to_vec(),
1143 })?
1144 .to_owned())
1145}
1146
1147fn parse_version(data: &[u8], endianness: object::Endianness) -> Result<Option<u32>, ParseError> {
1148 let data = match data.len() {
1149 4 => data.try_into().unwrap(),
1150 _ => {
1151 return Err(ParseError::InvalidKernelVersion {
1152 data: data.to_vec(),
1153 })
1154 }
1155 };
1156
1157 let v = match endianness {
1158 object::Endianness::Big => u32::from_be_bytes(data),
1159 object::Endianness::Little => u32::from_le_bytes(data),
1160 };
1161
1162 Ok(if v == KERNEL_VERSION_ANY {
1163 None
1164 } else {
1165 Some(v)
1166 })
1167}
1168
1169fn get_map_field(btf: &Btf, type_id: u32) -> Result<u32, BtfError> {
1173 let pty = match &btf.type_by_id(type_id)? {
1174 BtfType::Ptr(pty) => pty,
1175 other => {
1176 return Err(BtfError::UnexpectedBtfType {
1177 type_id: other.btf_type().unwrap_or(0),
1178 })
1179 }
1180 };
1181 let arr = match &btf.type_by_id(pty.btf_type)? {
1183 BtfType::Array(Array { array, .. }) => array,
1184 other => {
1185 return Err(BtfError::UnexpectedBtfType {
1186 type_id: other.btf_type().unwrap_or(0),
1187 })
1188 }
1189 };
1190 Ok(arr.len)
1191}
1192
1193fn parse_data_map_section(section: &Section) -> Result<Map, ParseError> {
1196 let (def, data) = match section.kind {
1197 EbpfSectionKind::Data | EbpfSectionKind::Rodata => {
1198 let def = bpf_map_def {
1199 map_type: BPF_MAP_TYPE_ARRAY as u32,
1200 key_size: mem::size_of::<u32>() as u32,
1201 value_size: section.size as u32,
1204 max_entries: 1,
1205 map_flags: if section.kind == EbpfSectionKind::Rodata {
1206 BPF_F_RDONLY_PROG
1207 } else {
1208 0
1209 },
1210 ..Default::default()
1211 };
1212 (def, section.data.to_vec())
1213 }
1214 EbpfSectionKind::Bss => {
1215 let def = bpf_map_def {
1216 map_type: BPF_MAP_TYPE_ARRAY as u32,
1217 key_size: mem::size_of::<u32>() as u32,
1218 value_size: section.size as u32,
1219 max_entries: 1,
1220 map_flags: 0,
1221 ..Default::default()
1222 };
1223 (def, vec![0; section.size as usize])
1224 }
1225 _ => unreachable!(),
1226 };
1227 Ok(Map::Legacy(LegacyMap {
1228 section_index: section.index.0,
1229 section_kind: section.kind,
1230 symbol_index: None,
1232 def,
1233 data,
1234 }))
1235}
1236
1237fn parse_map_def(name: &str, data: &[u8]) -> Result<bpf_map_def, ParseError> {
1238 if data.len() < MINIMUM_MAP_SIZE {
1239 return Err(ParseError::InvalidMapDefinition {
1240 name: name.to_owned(),
1241 });
1242 }
1243
1244 if data.len() < mem::size_of::<bpf_map_def>() {
1245 let mut map_def = bpf_map_def::default();
1246 unsafe {
1247 let map_def_ptr =
1248 from_raw_parts_mut(&mut map_def as *mut bpf_map_def as *mut u8, data.len());
1249 map_def_ptr.copy_from_slice(data);
1250 }
1251 Ok(map_def)
1252 } else {
1253 Ok(unsafe { ptr::read_unaligned(data.as_ptr() as *const bpf_map_def) })
1254 }
1255}
1256
1257fn parse_btf_map_def(btf: &Btf, info: &DataSecEntry) -> Result<(String, BtfMapDef), BtfError> {
1258 let ty = match btf.type_by_id(info.btf_type)? {
1259 BtfType::Var(var) => var,
1260 other => {
1261 return Err(BtfError::UnexpectedBtfType {
1262 type_id: other.btf_type().unwrap_or(0),
1263 })
1264 }
1265 };
1266 let map_name = btf.string_at(ty.name_offset)?;
1267 let mut map_def = BtfMapDef::default();
1268
1269 let root_type = btf.resolve_type(ty.btf_type)?;
1271 let s = match btf.type_by_id(root_type)? {
1272 BtfType::Struct(s) => s,
1273 other => {
1274 return Err(BtfError::UnexpectedBtfType {
1275 type_id: other.btf_type().unwrap_or(0),
1276 })
1277 }
1278 };
1279
1280 for m in &s.members {
1281 match btf.string_at(m.name_offset)?.as_ref() {
1282 "type" => {
1283 map_def.map_type = get_map_field(btf, m.btf_type)?;
1284 }
1285 "key" => {
1286 if let BtfType::Ptr(pty) = btf.type_by_id(m.btf_type)? {
1287 let t = pty.btf_type;
1289 map_def.key_size = btf.type_size(t)? as u32;
1290 map_def.btf_key_type_id = t;
1291 } else {
1292 return Err(BtfError::UnexpectedBtfType {
1293 type_id: m.btf_type,
1294 });
1295 }
1296 }
1297 "key_size" => {
1298 map_def.key_size = get_map_field(btf, m.btf_type)?;
1299 }
1300 "value" => {
1301 if let BtfType::Ptr(pty) = btf.type_by_id(m.btf_type)? {
1302 let t = pty.btf_type;
1303 map_def.value_size = btf.type_size(t)? as u32;
1304 map_def.btf_value_type_id = t;
1305 } else {
1306 return Err(BtfError::UnexpectedBtfType {
1307 type_id: m.btf_type,
1308 });
1309 }
1310 }
1311 "value_size" => {
1312 map_def.value_size = get_map_field(btf, m.btf_type)?;
1313 }
1314 "max_entries" => {
1315 map_def.max_entries = get_map_field(btf, m.btf_type)?;
1316 }
1317 "map_flags" => {
1318 map_def.map_flags = get_map_field(btf, m.btf_type)?;
1319 }
1320 "pinning" => {
1321 let pinning = get_map_field(btf, m.btf_type)?;
1322 map_def.pinning = PinningType::try_from(pinning).unwrap_or_else(|_| {
1323 debug!("{} is not a valid pin type. using PIN_NONE", pinning);
1324 PinningType::None
1325 });
1326 }
1327 other => {
1328 debug!("skipping unknown map section: {}", other);
1329 continue;
1330 }
1331 }
1332 }
1333 Ok((map_name.to_string(), map_def))
1334}
1335
1336pub fn parse_map_info(info: bpf_map_info, pinned: PinningType) -> Map {
1338 if info.btf_key_type_id != 0 {
1339 Map::Btf(BtfMap {
1340 def: BtfMapDef {
1341 map_type: info.type_,
1342 key_size: info.key_size,
1343 value_size: info.value_size,
1344 max_entries: info.max_entries,
1345 map_flags: info.map_flags,
1346 pinning: pinned,
1347 btf_key_type_id: info.btf_key_type_id,
1348 btf_value_type_id: info.btf_value_type_id,
1349 },
1350 section_index: 0,
1351 symbol_index: 0,
1352 data: Vec::new(),
1353 })
1354 } else {
1355 Map::Legacy(LegacyMap {
1356 def: bpf_map_def {
1357 map_type: info.type_,
1358 key_size: info.key_size,
1359 value_size: info.value_size,
1360 max_entries: info.max_entries,
1361 map_flags: info.map_flags,
1362 pinning: pinned,
1363 id: info.id,
1364 },
1365 section_index: 0,
1366 symbol_index: None,
1367 section_kind: EbpfSectionKind::Undefined,
1368 data: Vec::new(),
1369 })
1370 }
1371}
1372
1373pub fn copy_instructions(data: &[u8]) -> Result<Vec<bpf_insn>, ParseError> {
1375 if data.len() % mem::size_of::<bpf_insn>() > 0 {
1376 return Err(ParseError::InvalidProgramCode);
1377 }
1378 let instructions = data
1379 .chunks_exact(mem::size_of::<bpf_insn>())
1380 .map(|d| unsafe { ptr::read_unaligned(d.as_ptr() as *const bpf_insn) })
1381 .collect::<Vec<_>>();
1382 Ok(instructions)
1383}
1384
1385fn get_func_and_line_info(
1386 btf_ext: Option<&BtfExt>,
1387 symbol: &Symbol,
1388 section: &Section,
1389 offset: usize,
1390 rewrite_insn_off: bool,
1391) -> (FuncSecInfo, LineSecInfo, usize, usize) {
1392 btf_ext
1393 .map(|btf_ext| {
1394 let instruction_offset = (offset / INS_SIZE) as u32;
1395 let symbol_size_instructions = (symbol.size as usize / INS_SIZE) as u32;
1396
1397 let mut func_info = btf_ext.func_info.get(section.name);
1398 func_info.func_info.retain_mut(|f| {
1399 let retain = f.insn_off == instruction_offset;
1400 if retain && rewrite_insn_off {
1401 f.insn_off = 0;
1402 }
1403 retain
1404 });
1405
1406 let mut line_info = btf_ext.line_info.get(section.name);
1407 line_info
1408 .line_info
1409 .retain_mut(|l| match l.insn_off.checked_sub(instruction_offset) {
1410 None => false,
1411 Some(insn_off) => {
1412 let retain = insn_off < symbol_size_instructions;
1413 if retain && rewrite_insn_off {
1414 l.insn_off = insn_off
1415 }
1416 retain
1417 }
1418 });
1419 (
1420 func_info,
1421 line_info,
1422 btf_ext.func_info_rec_size(),
1423 btf_ext.line_info_rec_size(),
1424 )
1425 })
1426 .unwrap_or_default()
1427}
1428
1429#[cfg(test)]
1430mod tests {
1431 use alloc::vec;
1432
1433 use assert_matches::assert_matches;
1434
1435 use super::*;
1436 use crate::generated::btf_ext_header;
1437
1438 const FAKE_INS_LEN: u64 = 8;
1439
1440 fn fake_section<'a>(
1441 kind: EbpfSectionKind,
1442 name: &'a str,
1443 data: &'a [u8],
1444 index: Option<usize>,
1445 ) -> Section<'a> {
1446 let idx = index.unwrap_or(0);
1447 Section {
1448 index: SectionIndex(idx),
1449 kind,
1450 address: 0,
1451 name,
1452 data,
1453 size: data.len() as u64,
1454 relocations: Vec::new(),
1455 }
1456 }
1457
1458 fn fake_ins() -> bpf_insn {
1459 bpf_insn {
1460 code: 0,
1461 _bitfield_align_1: [],
1462 _bitfield_1: bpf_insn::new_bitfield_1(0, 0),
1463 off: 0,
1464 imm: 0,
1465 }
1466 }
1467
1468 fn fake_sym(obj: &mut Object, section_index: usize, address: u64, name: &str, size: u64) {
1469 let idx = obj.symbol_table.len();
1470 obj.symbol_table.insert(
1471 idx + 1,
1472 Symbol {
1473 index: idx + 1,
1474 section_index: Some(section_index),
1475 name: Some(name.to_string()),
1476 address,
1477 size,
1478 is_definition: false,
1479 kind: SymbolKind::Text,
1480 },
1481 );
1482 obj.symbols_by_section
1483 .entry(SectionIndex(section_index))
1484 .or_default()
1485 .push(idx + 1);
1486 }
1487
1488 fn bytes_of<T>(val: &T) -> &[u8] {
1489 unsafe { crate::util::bytes_of(val) }
1491 }
1492
1493 #[test]
1494 fn test_parse_generic_error() {
1495 assert_matches!(Object::parse(&b"foo"[..]), Err(ParseError::ElfError(_)))
1496 }
1497
1498 #[test]
1499 fn test_parse_license() {
1500 assert_matches!(parse_license(b""), Err(ParseError::InvalidLicense { .. }));
1501
1502 assert_matches!(parse_license(b"\0"), Err(ParseError::InvalidLicense { .. }));
1503
1504 assert_matches!(
1505 parse_license(b"GPL"),
1506 Err(ParseError::MissingLicenseNullTerminator { .. })
1507 );
1508
1509 assert_eq!(parse_license(b"GPL\0").unwrap().to_str().unwrap(), "GPL");
1510 }
1511
1512 #[test]
1513 fn test_parse_version() {
1514 assert_matches!(
1515 parse_version(b"", Endianness::Little),
1516 Err(ParseError::InvalidKernelVersion { .. })
1517 );
1518
1519 assert_matches!(
1520 parse_version(b"123", Endianness::Little),
1521 Err(ParseError::InvalidKernelVersion { .. })
1522 );
1523
1524 assert_matches!(
1525 parse_version(&0xFFFF_FFFEu32.to_le_bytes(), Endianness::Little),
1526 Ok(None)
1527 );
1528
1529 assert_matches!(
1530 parse_version(&0xFFFF_FFFEu32.to_be_bytes(), Endianness::Big),
1531 Ok(None)
1532 );
1533
1534 assert_matches!(
1535 parse_version(&1234u32.to_le_bytes(), Endianness::Little),
1536 Ok(Some(1234))
1537 );
1538 }
1539
1540 #[test]
1541 fn test_parse_map_def_error() {
1542 assert_matches!(
1543 parse_map_def("foo", &[]),
1544 Err(ParseError::InvalidMapDefinition { .. })
1545 );
1546 }
1547
1548 #[test]
1549 fn test_parse_map_short() {
1550 let def = bpf_map_def {
1551 map_type: 1,
1552 key_size: 2,
1553 value_size: 3,
1554 max_entries: 4,
1555 map_flags: 5,
1556 id: 0,
1557 pinning: PinningType::None,
1558 };
1559
1560 assert_eq!(
1561 parse_map_def("foo", &bytes_of(&def)[..MINIMUM_MAP_SIZE]).unwrap(),
1562 def
1563 );
1564 }
1565
1566 #[test]
1567 fn test_parse_map_def() {
1568 let def = bpf_map_def {
1569 map_type: 1,
1570 key_size: 2,
1571 value_size: 3,
1572 max_entries: 4,
1573 map_flags: 5,
1574 id: 6,
1575 pinning: PinningType::ByName,
1576 };
1577
1578 assert_eq!(parse_map_def("foo", bytes_of(&def)).unwrap(), def);
1579 }
1580
1581 #[test]
1582 fn test_parse_map_def_with_padding() {
1583 let def = bpf_map_def {
1584 map_type: 1,
1585 key_size: 2,
1586 value_size: 3,
1587 max_entries: 4,
1588 map_flags: 5,
1589 id: 6,
1590 pinning: PinningType::ByName,
1591 };
1592 let mut buf = [0u8; 128];
1593 unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, def) };
1594
1595 assert_eq!(parse_map_def("foo", &buf).unwrap(), def);
1596 }
1597
1598 #[test]
1599 fn test_parse_map_data() {
1600 let map_data = b"map data";
1601 assert_matches!(
1602 parse_data_map_section(
1603 &fake_section(
1604 EbpfSectionKind::Data,
1605 ".bss",
1606 map_data,
1607 None,
1608 ),
1609 ),
1610 Ok(Map::Legacy(LegacyMap {
1611 section_index: 0,
1612 section_kind: EbpfSectionKind::Data,
1613 symbol_index: None,
1614 def: bpf_map_def {
1615 map_type: _map_type,
1616 key_size: 4,
1617 value_size,
1618 max_entries: 1,
1619 map_flags: 0,
1620 id: 0,
1621 pinning: PinningType::None,
1622 },
1623 data,
1624 })) if data == map_data && value_size == map_data.len() as u32
1625 )
1626 }
1627
1628 fn fake_obj() -> Object {
1629 Object::new(Endianness::Little, CString::new("GPL").unwrap(), None)
1630 }
1631
1632 #[test]
1633 fn sanitizes_empty_btf_files_to_none() {
1634 let mut obj = fake_obj();
1635
1636 let btf = Btf::new();
1637 let btf_bytes = btf.to_bytes();
1638 obj.parse_section(fake_section(EbpfSectionKind::Btf, ".BTF", &btf_bytes, None))
1639 .unwrap();
1640
1641 const FUNC_INFO_LEN: u32 = 4;
1642 const LINE_INFO_LEN: u32 = 4;
1643 const CORE_RELO_LEN: u32 = 16;
1644 let ext_header = btf_ext_header {
1645 magic: 0xeb9f,
1646 version: 1,
1647 flags: 0,
1648 hdr_len: 24,
1649 func_info_off: 0,
1650 func_info_len: FUNC_INFO_LEN,
1651 line_info_off: FUNC_INFO_LEN,
1652 line_info_len: LINE_INFO_LEN,
1653 core_relo_off: FUNC_INFO_LEN + LINE_INFO_LEN,
1654 core_relo_len: CORE_RELO_LEN,
1655 };
1656 let btf_ext_bytes = bytes_of::<btf_ext_header>(&ext_header).to_vec();
1657 obj.parse_section(fake_section(
1658 EbpfSectionKind::BtfExt,
1659 ".BTF.ext",
1660 &btf_ext_bytes,
1661 None,
1662 ))
1663 .unwrap();
1664
1665 let btf = obj.fixup_and_sanitize_btf(&BtfFeatures::default()).unwrap();
1666 assert!(btf.is_none());
1667 }
1668
1669 #[test]
1670 fn test_parse_program_error() {
1671 let mut obj = fake_obj();
1672 fake_sym(&mut obj, 0, 0, "foo", 1);
1673 assert_matches!(
1674 obj.parse_programs(&fake_section(
1675 EbpfSectionKind::Program,
1676 "kprobe/foo",
1677 &42u32.to_ne_bytes(),
1678 None,
1679 ),),
1680 Err(ParseError::InvalidProgramCode)
1681 );
1682 }
1683
1684 #[test]
1685 fn test_parse_program() {
1686 let mut obj = fake_obj();
1687 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
1688
1689 obj.parse_programs(&fake_section(
1690 EbpfSectionKind::Program,
1691 "kprobe/foo",
1692 bytes_of(&fake_ins()),
1693 None,
1694 ))
1695 .unwrap();
1696
1697 let prog_foo = obj.programs.get("foo").unwrap();
1698
1699 assert_matches!(prog_foo, Program {
1700 license,
1701 kernel_version: None,
1702 section: ProgramSection::KProbe { .. },
1703 ..
1704 } => assert_eq!(license.to_str().unwrap(), "GPL"));
1705
1706 assert_matches!(
1707 obj.functions.get(&prog_foo.function_key()),
1708 Some(Function {
1709 name,
1710 address: 0,
1711 section_index: SectionIndex(0),
1712 section_offset: 0,
1713 instructions,
1714 ..}) if name == "foo" && instructions.len() == 1
1715 )
1716 }
1717
1718 #[test]
1719 fn test_parse_section_map() {
1720 let mut obj = fake_obj();
1721 fake_sym(&mut obj, 0, 0, "foo", mem::size_of::<bpf_map_def>() as u64);
1722 assert_matches!(
1723 obj.parse_section(fake_section(
1724 EbpfSectionKind::Maps,
1725 "maps/foo",
1726 bytes_of(&bpf_map_def {
1727 map_type: 1,
1728 key_size: 2,
1729 value_size: 3,
1730 max_entries: 4,
1731 map_flags: 5,
1732 ..Default::default()
1733 }),
1734 None,
1735 )),
1736 Ok(())
1737 );
1738 assert!(obj.maps.contains_key("foo"));
1739 }
1740
1741 #[test]
1742 fn test_parse_multiple_program_in_same_section() {
1743 let mut obj = fake_obj();
1744 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
1745 fake_sym(&mut obj, 0, FAKE_INS_LEN, "bar", FAKE_INS_LEN);
1746
1747 let insns = [fake_ins(), fake_ins()];
1748 let data = bytes_of(&insns);
1749
1750 obj.parse_programs(&fake_section(
1751 EbpfSectionKind::Program,
1752 "kprobe",
1753 data,
1754 None,
1755 ))
1756 .unwrap();
1757
1758 let prog_foo = obj.programs.get("foo").unwrap();
1759 let function_foo = obj.functions.get(&prog_foo.function_key()).unwrap();
1760 let prog_bar = obj.programs.get("bar").unwrap();
1761 let function_bar = obj.functions.get(&prog_bar.function_key()).unwrap();
1762
1763 assert_matches!(prog_foo, Program {
1764 license,
1765 kernel_version: None,
1766 section: ProgramSection::KProbe { .. },
1767 ..
1768 } => assert_eq!(license.to_str().unwrap(), "GPL"));
1769 assert_matches!(
1770 function_foo,
1771 Function {
1772 name,
1773 address: 0,
1774 section_index: SectionIndex(0),
1775 section_offset: 0,
1776 instructions,
1777 ..
1778 } if name == "foo" && instructions.len() == 1
1779 );
1780
1781 assert_matches!(prog_bar, Program {
1782 license,
1783 kernel_version: None,
1784 section: ProgramSection::KProbe { .. },
1785 ..
1786 } => assert_eq!(license.to_str().unwrap(), "GPL"));
1787 assert_matches!(
1788 function_bar,
1789 Function {
1790 name,
1791 address: 8,
1792 section_index: SectionIndex(0),
1793 section_offset: 8,
1794 instructions,
1795 ..
1796 } if name == "bar" && instructions.len() == 1
1797 );
1798 }
1799
1800 #[test]
1801 fn test_parse_section_multiple_maps() {
1802 let mut obj = fake_obj();
1803 fake_sym(&mut obj, 0, 0, "foo", mem::size_of::<bpf_map_def>() as u64);
1804 fake_sym(&mut obj, 0, 28, "bar", mem::size_of::<bpf_map_def>() as u64);
1805 fake_sym(&mut obj, 0, 60, "baz", mem::size_of::<bpf_map_def>() as u64);
1806 let def = &bpf_map_def {
1807 map_type: 1,
1808 key_size: 2,
1809 value_size: 3,
1810 max_entries: 4,
1811 map_flags: 5,
1812 ..Default::default()
1813 };
1814 let map_data = bytes_of(def).to_vec();
1815 let mut buf = vec![];
1816 buf.extend(&map_data);
1817 buf.extend(&map_data);
1818 buf.extend([0, 0, 0, 0]);
1820 buf.extend(&map_data);
1821 assert_matches!(
1822 obj.parse_section(fake_section(
1823 EbpfSectionKind::Maps,
1824 "maps",
1825 buf.as_slice(),
1826 None
1827 )),
1828 Ok(())
1829 );
1830 assert!(obj.maps.contains_key("foo"));
1831 assert!(obj.maps.contains_key("bar"));
1832 assert!(obj.maps.contains_key("baz"));
1833 for map in obj.maps.values() {
1834 assert_matches!(map, Map::Legacy(m) => {
1835 assert_eq!(&m.def, def);
1836 })
1837 }
1838 }
1839
1840 #[test]
1841 fn test_parse_section_data() {
1842 let mut obj = fake_obj();
1843 assert_matches!(
1844 obj.parse_section(fake_section(
1845 EbpfSectionKind::Data,
1846 ".bss",
1847 b"map data",
1848 None
1849 )),
1850 Ok(())
1851 );
1852 assert!(obj.maps.contains_key(".bss"));
1853
1854 assert_matches!(
1855 obj.parse_section(fake_section(
1856 EbpfSectionKind::Data,
1857 ".rodata",
1858 b"map data",
1859 None
1860 )),
1861 Ok(())
1862 );
1863 assert!(obj.maps.contains_key(".rodata"));
1864
1865 assert_matches!(
1866 obj.parse_section(fake_section(
1867 EbpfSectionKind::Data,
1868 ".rodata.boo",
1869 b"map data",
1870 None
1871 )),
1872 Ok(())
1873 );
1874 assert!(obj.maps.contains_key(".rodata.boo"));
1875
1876 assert_matches!(
1877 obj.parse_section(fake_section(
1878 EbpfSectionKind::Data,
1879 ".data",
1880 b"map data",
1881 None
1882 )),
1883 Ok(())
1884 );
1885 assert!(obj.maps.contains_key(".data"));
1886
1887 assert_matches!(
1888 obj.parse_section(fake_section(
1889 EbpfSectionKind::Data,
1890 ".data.boo",
1891 b"map data",
1892 None
1893 )),
1894 Ok(())
1895 );
1896 assert!(obj.maps.contains_key(".data.boo"));
1897 }
1898
1899 #[test]
1900 fn test_parse_section_kprobe() {
1901 let mut obj = fake_obj();
1902 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
1903
1904 assert_matches!(
1905 obj.parse_section(fake_section(
1906 EbpfSectionKind::Program,
1907 "kprobe/foo",
1908 bytes_of(&fake_ins()),
1909 None
1910 )),
1911 Ok(())
1912 );
1913 assert_matches!(
1914 obj.programs.get("foo"),
1915 Some(Program {
1916 section: ProgramSection::KProbe { .. },
1917 ..
1918 })
1919 );
1920 }
1921
1922 #[test]
1923 fn test_parse_section_uprobe() {
1924 let mut obj = fake_obj();
1925 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
1926
1927 assert_matches!(
1928 obj.parse_section(fake_section(
1929 EbpfSectionKind::Program,
1930 "uprobe/foo",
1931 bytes_of(&fake_ins()),
1932 None
1933 )),
1934 Ok(())
1935 );
1936 assert_matches!(
1937 obj.programs.get("foo"),
1938 Some(Program {
1939 section: ProgramSection::UProbe { .. },
1940 ..
1941 })
1942 );
1943 }
1944
1945 #[test]
1946 fn test_parse_section_uprobe_sleepable() {
1947 let mut obj = fake_obj();
1948 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
1949
1950 assert_matches!(
1951 obj.parse_section(fake_section(
1952 EbpfSectionKind::Program,
1953 "uprobe.s/foo",
1954 bytes_of(&fake_ins()),
1955 None
1956 )),
1957 Ok(())
1958 );
1959 assert_matches!(
1960 obj.programs.get("foo"),
1961 Some(Program {
1962 section: ProgramSection::UProbe {
1963 sleepable: true,
1964 ..
1965 },
1966 ..
1967 })
1968 );
1969 }
1970
1971 #[test]
1972 fn test_parse_section_uretprobe() {
1973 let mut obj = fake_obj();
1974 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
1975
1976 assert_matches!(
1977 obj.parse_section(fake_section(
1978 EbpfSectionKind::Program,
1979 "uretprobe/foo",
1980 bytes_of(&fake_ins()),
1981 None
1982 )),
1983 Ok(())
1984 );
1985 assert_matches!(
1986 obj.programs.get("foo"),
1987 Some(Program {
1988 section: ProgramSection::URetProbe { .. },
1989 ..
1990 })
1991 );
1992 }
1993
1994 #[test]
1995 fn test_parse_section_uretprobe_sleepable() {
1996 let mut obj = fake_obj();
1997 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
1998
1999 assert_matches!(
2000 obj.parse_section(fake_section(
2001 EbpfSectionKind::Program,
2002 "uretprobe.s/foo",
2003 bytes_of(&fake_ins()),
2004 None
2005 )),
2006 Ok(())
2007 );
2008 assert_matches!(
2009 obj.programs.get("foo"),
2010 Some(Program {
2011 section: ProgramSection::URetProbe {
2012 sleepable: true,
2013 ..
2014 },
2015 ..
2016 })
2017 );
2018 }
2019
2020 #[test]
2021 fn test_parse_section_trace_point() {
2022 let mut obj = fake_obj();
2023 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
2024 fake_sym(&mut obj, 1, 0, "bar", FAKE_INS_LEN);
2025
2026 assert_matches!(
2027 obj.parse_section(fake_section(
2028 EbpfSectionKind::Program,
2029 "tracepoint/foo",
2030 bytes_of(&fake_ins()),
2031 None
2032 )),
2033 Ok(())
2034 );
2035 assert_matches!(
2036 obj.programs.get("foo"),
2037 Some(Program {
2038 section: ProgramSection::TracePoint { .. },
2039 ..
2040 })
2041 );
2042
2043 assert_matches!(
2044 obj.parse_section(fake_section(
2045 EbpfSectionKind::Program,
2046 "tp/foo/bar",
2047 bytes_of(&fake_ins()),
2048 Some(1),
2049 )),
2050 Ok(())
2051 );
2052 assert_matches!(
2053 obj.programs.get("bar"),
2054 Some(Program {
2055 section: ProgramSection::TracePoint { .. },
2056 ..
2057 })
2058 );
2059 }
2060
2061 #[test]
2062 fn test_parse_section_socket_filter() {
2063 let mut obj = fake_obj();
2064 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
2065
2066 assert_matches!(
2067 obj.parse_section(fake_section(
2068 EbpfSectionKind::Program,
2069 "socket/foo",
2070 bytes_of(&fake_ins()),
2071 None
2072 )),
2073 Ok(())
2074 );
2075 assert_matches!(
2076 obj.programs.get("foo"),
2077 Some(Program {
2078 section: ProgramSection::SocketFilter { .. },
2079 ..
2080 })
2081 );
2082 }
2083
2084 #[test]
2085 fn test_parse_section_xdp() {
2086 let mut obj = fake_obj();
2087 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
2088
2089 assert_matches!(
2090 obj.parse_section(fake_section(
2091 EbpfSectionKind::Program,
2092 "xdp",
2093 bytes_of(&fake_ins()),
2094 None
2095 )),
2096 Ok(())
2097 );
2098 assert_matches!(
2099 obj.programs.get("foo"),
2100 Some(Program {
2101 section: ProgramSection::Xdp { frags: false, .. },
2102 ..
2103 })
2104 );
2105 }
2106
2107 #[test]
2108 fn test_parse_section_xdp_frags() {
2109 let mut obj = fake_obj();
2110 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
2111
2112 assert_matches!(
2113 obj.parse_section(fake_section(
2114 EbpfSectionKind::Program,
2115 "xdp.frags",
2116 bytes_of(&fake_ins()),
2117 None
2118 )),
2119 Ok(())
2120 );
2121 assert_matches!(
2122 obj.programs.get("foo"),
2123 Some(Program {
2124 section: ProgramSection::Xdp { frags: true, .. },
2125 ..
2126 })
2127 );
2128 }
2129
2130 #[test]
2131 fn test_parse_section_raw_tp() {
2132 let mut obj = fake_obj();
2133 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
2134 fake_sym(&mut obj, 1, 0, "bar", FAKE_INS_LEN);
2135
2136 assert_matches!(
2137 obj.parse_section(fake_section(
2138 EbpfSectionKind::Program,
2139 "raw_tp/foo",
2140 bytes_of(&fake_ins()),
2141 None
2142 )),
2143 Ok(())
2144 );
2145 assert_matches!(
2146 obj.programs.get("foo"),
2147 Some(Program {
2148 section: ProgramSection::RawTracePoint { .. },
2149 ..
2150 })
2151 );
2152
2153 assert_matches!(
2154 obj.parse_section(fake_section(
2155 EbpfSectionKind::Program,
2156 "raw_tracepoint/bar",
2157 bytes_of(&fake_ins()),
2158 Some(1)
2159 )),
2160 Ok(())
2161 );
2162 assert_matches!(
2163 obj.programs.get("bar"),
2164 Some(Program {
2165 section: ProgramSection::RawTracePoint { .. },
2166 ..
2167 })
2168 );
2169 }
2170
2171 #[test]
2172 fn test_parse_section_lsm() {
2173 let mut obj = fake_obj();
2174 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
2175
2176 assert_matches!(
2177 obj.parse_section(fake_section(
2178 EbpfSectionKind::Program,
2179 "lsm/foo",
2180 bytes_of(&fake_ins()),
2181 None
2182 )),
2183 Ok(())
2184 );
2185 assert_matches!(
2186 obj.programs.get("foo"),
2187 Some(Program {
2188 section: ProgramSection::Lsm {
2189 sleepable: false,
2190 ..
2191 },
2192 ..
2193 })
2194 );
2195 }
2196
2197 #[test]
2198 fn test_parse_section_lsm_sleepable() {
2199 let mut obj = fake_obj();
2200 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
2201
2202 assert_matches!(
2203 obj.parse_section(fake_section(
2204 EbpfSectionKind::Program,
2205 "lsm.s/foo",
2206 bytes_of(&fake_ins()),
2207 None
2208 )),
2209 Ok(())
2210 );
2211 assert_matches!(
2212 obj.programs.get("foo"),
2213 Some(Program {
2214 section: ProgramSection::Lsm {
2215 sleepable: true,
2216 ..
2217 },
2218 ..
2219 })
2220 );
2221 }
2222
2223 #[test]
2224 fn test_parse_section_btf_tracepoint() {
2225 let mut obj = fake_obj();
2226 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
2227
2228 assert_matches!(
2229 obj.parse_section(fake_section(
2230 EbpfSectionKind::Program,
2231 "tp_btf/foo",
2232 bytes_of(&fake_ins()),
2233 None
2234 )),
2235 Ok(())
2236 );
2237 assert_matches!(
2238 obj.programs.get("foo"),
2239 Some(Program {
2240 section: ProgramSection::BtfTracePoint { .. },
2241 ..
2242 })
2243 );
2244 }
2245
2246 #[test]
2247 fn test_parse_section_skskb_unnamed() {
2248 let mut obj = fake_obj();
2249 fake_sym(&mut obj, 0, 0, "stream_parser", FAKE_INS_LEN);
2250
2251 assert_matches!(
2252 obj.parse_section(fake_section(
2253 EbpfSectionKind::Program,
2254 "sk_skb/stream_parser",
2255 bytes_of(&fake_ins()),
2256 None
2257 )),
2258 Ok(())
2259 );
2260 assert_matches!(
2261 obj.programs.get("stream_parser"),
2262 Some(Program {
2263 section: ProgramSection::SkSkbStreamParser { .. },
2264 ..
2265 })
2266 );
2267 }
2268
2269 #[test]
2270 fn test_parse_section_skskb_named() {
2271 let mut obj = fake_obj();
2272 fake_sym(&mut obj, 0, 0, "my_parser", FAKE_INS_LEN);
2273
2274 assert_matches!(
2275 obj.parse_section(fake_section(
2276 EbpfSectionKind::Program,
2277 "sk_skb/stream_parser/my_parser",
2278 bytes_of(&fake_ins()),
2279 None
2280 )),
2281 Ok(())
2282 );
2283 assert_matches!(
2284 obj.programs.get("my_parser"),
2285 Some(Program {
2286 section: ProgramSection::SkSkbStreamParser { .. },
2287 ..
2288 })
2289 );
2290 }
2291
2292 #[test]
2293 fn test_parse_section_fentry() {
2294 let mut obj = fake_obj();
2295 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
2296
2297 assert_matches!(
2298 obj.parse_section(fake_section(
2299 EbpfSectionKind::Program,
2300 "fentry/foo",
2301 bytes_of(&fake_ins()),
2302 None
2303 )),
2304 Ok(())
2305 );
2306 assert_matches!(
2307 obj.programs.get("foo"),
2308 Some(Program {
2309 section: ProgramSection::FEntry { .. },
2310 ..
2311 })
2312 );
2313 }
2314
2315 #[test]
2316 fn test_parse_section_fentry_sleepable() {
2317 let mut obj = fake_obj();
2318 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
2319
2320 assert_matches!(
2321 obj.parse_section(fake_section(
2322 EbpfSectionKind::Program,
2323 "fentry.s/foo",
2324 bytes_of(&fake_ins()),
2325 None
2326 )),
2327 Ok(())
2328 );
2329 assert_matches!(
2330 obj.programs.get("foo"),
2331 Some(Program {
2332 section: ProgramSection::FEntry {
2333 sleepable: true,
2334 ..
2335 },
2336 ..
2337 })
2338 );
2339 }
2340
2341 #[test]
2342 fn test_parse_section_fexit() {
2343 let mut obj = fake_obj();
2344 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
2345
2346 assert_matches!(
2347 obj.parse_section(fake_section(
2348 EbpfSectionKind::Program,
2349 "fexit/foo",
2350 bytes_of(&fake_ins()),
2351 None
2352 )),
2353 Ok(())
2354 );
2355 assert_matches!(
2356 obj.programs.get("foo"),
2357 Some(Program {
2358 section: ProgramSection::FExit { .. },
2359 ..
2360 })
2361 );
2362 }
2363
2364 #[test]
2365 fn test_parse_section_fexit_sleepable() {
2366 let mut obj = fake_obj();
2367 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
2368
2369 assert_matches!(
2370 obj.parse_section(fake_section(
2371 EbpfSectionKind::Program,
2372 "fexit.s/foo",
2373 bytes_of(&fake_ins()),
2374 None
2375 )),
2376 Ok(())
2377 );
2378 assert_matches!(
2379 obj.programs.get("foo"),
2380 Some(Program {
2381 section: ProgramSection::FExit {
2382 sleepable: true,
2383 ..
2384 },
2385 ..
2386 })
2387 );
2388 }
2389
2390 #[test]
2391 fn test_parse_section_cgroup_skb_ingress_unnamed() {
2392 let mut obj = fake_obj();
2393 fake_sym(&mut obj, 0, 0, "ingress", FAKE_INS_LEN);
2394
2395 assert_matches!(
2396 obj.parse_section(fake_section(
2397 EbpfSectionKind::Program,
2398 "cgroup_skb/ingress",
2399 bytes_of(&fake_ins()),
2400 None
2401 )),
2402 Ok(())
2403 );
2404 assert_matches!(
2405 obj.programs.get("ingress"),
2406 Some(Program {
2407 section: ProgramSection::CgroupSkbIngress { .. },
2408 ..
2409 })
2410 );
2411 }
2412
2413 #[test]
2414 fn test_parse_section_cgroup_skb_ingress_named() {
2415 let mut obj = fake_obj();
2416 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
2417
2418 assert_matches!(
2419 obj.parse_section(fake_section(
2420 EbpfSectionKind::Program,
2421 "cgroup_skb/ingress/foo",
2422 bytes_of(&fake_ins()),
2423 None
2424 )),
2425 Ok(())
2426 );
2427 assert_matches!(
2428 obj.programs.get("foo"),
2429 Some(Program {
2430 section: ProgramSection::CgroupSkbIngress { .. },
2431 ..
2432 })
2433 );
2434 }
2435
2436 #[test]
2437 fn test_parse_section_cgroup_skb_no_direction_unamed() {
2438 let mut obj = fake_obj();
2439 fake_sym(&mut obj, 0, 0, "skb", FAKE_INS_LEN);
2440
2441 assert_matches!(
2442 obj.parse_section(fake_section(
2443 EbpfSectionKind::Program,
2444 "cgroup/skb",
2445 bytes_of(&fake_ins()),
2446 None
2447 )),
2448 Ok(())
2449 );
2450 assert_matches!(
2451 obj.programs.get("skb"),
2452 Some(Program {
2453 section: ProgramSection::CgroupSkb { .. },
2454 ..
2455 })
2456 );
2457 }
2458
2459 #[test]
2460 fn test_parse_section_cgroup_skb_no_direction_named() {
2461 let mut obj = fake_obj();
2462 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
2463
2464 assert_matches!(
2465 obj.parse_section(fake_section(
2466 EbpfSectionKind::Program,
2467 "cgroup/skb/foo",
2468 bytes_of(&fake_ins()),
2469 None
2470 )),
2471 Ok(())
2472 );
2473 assert_matches!(
2474 obj.programs.get("foo"),
2475 Some(Program {
2476 section: ProgramSection::CgroupSkb { .. },
2477 ..
2478 })
2479 );
2480 }
2481
2482 #[test]
2483 fn test_parse_section_sock_addr_named() {
2484 let mut obj = fake_obj();
2485 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
2486
2487 assert_matches!(
2488 obj.parse_section(fake_section(
2489 EbpfSectionKind::Program,
2490 "cgroup/connect4/foo",
2491 bytes_of(&fake_ins()),
2492 None
2493 )),
2494 Ok(())
2495 );
2496 assert_matches!(
2497 obj.programs.get("foo"),
2498 Some(Program {
2499 section: ProgramSection::CgroupSockAddr {
2500 attach_type: CgroupSockAddrAttachType::Connect4,
2501 ..
2502 },
2503 ..
2504 })
2505 );
2506 }
2507
2508 #[test]
2509 fn test_parse_section_sock_addr_unnamed() {
2510 let mut obj = fake_obj();
2511 fake_sym(&mut obj, 0, 0, "connect4", FAKE_INS_LEN);
2512
2513 assert_matches!(
2514 obj.parse_section(fake_section(
2515 EbpfSectionKind::Program,
2516 "cgroup/connect4",
2517 bytes_of(&fake_ins()),
2518 None
2519 )),
2520 Ok(())
2521 );
2522 assert_matches!(
2523 obj.programs.get("connect4"),
2524 Some(Program {
2525 section: ProgramSection::CgroupSockAddr {
2526 attach_type: CgroupSockAddrAttachType::Connect4,
2527 ..
2528 },
2529 ..
2530 })
2531 );
2532 }
2533
2534 #[test]
2535 fn test_parse_section_sockopt_named() {
2536 let mut obj = fake_obj();
2537 fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
2538
2539 assert_matches!(
2540 obj.parse_section(fake_section(
2541 EbpfSectionKind::Program,
2542 "cgroup/getsockopt/foo",
2543 bytes_of(&fake_ins()),
2544 None
2545 )),
2546 Ok(())
2547 );
2548 assert_matches!(
2549 obj.programs.get("foo"),
2550 Some(Program {
2551 section: ProgramSection::CgroupSockopt {
2552 attach_type: CgroupSockoptAttachType::Get,
2553 ..
2554 },
2555 ..
2556 })
2557 );
2558 }
2559
2560 #[test]
2561 fn test_parse_section_sockopt_unnamed() {
2562 let mut obj = fake_obj();
2563 fake_sym(&mut obj, 0, 0, "getsockopt", FAKE_INS_LEN);
2564
2565 assert_matches!(
2566 obj.parse_section(fake_section(
2567 EbpfSectionKind::Program,
2568 "cgroup/getsockopt",
2569 bytes_of(&fake_ins()),
2570 None
2571 )),
2572 Ok(())
2573 );
2574 assert_matches!(
2575 obj.programs.get("getsockopt"),
2576 Some(Program {
2577 section: ProgramSection::CgroupSockopt {
2578 attach_type: CgroupSockoptAttachType::Get,
2579 ..
2580 },
2581 ..
2582 })
2583 );
2584 }
2585
2586 #[test]
2587 fn test_patch_map_data() {
2588 let mut obj = fake_obj();
2589 obj.maps.insert(
2590 ".rodata".to_owned(),
2591 Map::Legacy(LegacyMap {
2592 def: bpf_map_def {
2593 map_type: BPF_MAP_TYPE_ARRAY as u32,
2594 key_size: mem::size_of::<u32>() as u32,
2595 value_size: 3,
2596 max_entries: 1,
2597 map_flags: BPF_F_RDONLY_PROG,
2598 id: 1,
2599 pinning: PinningType::None,
2600 },
2601 section_index: 1,
2602 section_kind: EbpfSectionKind::Rodata,
2603 symbol_index: Some(1),
2604 data: vec![0, 0, 0],
2605 }),
2606 );
2607 obj.symbol_table.insert(
2608 1,
2609 Symbol {
2610 index: 1,
2611 section_index: Some(1),
2612 name: Some("my_config".to_owned()),
2613 address: 0,
2614 size: 3,
2615 is_definition: true,
2616 kind: SymbolKind::Data,
2617 },
2618 );
2619
2620 let test_data: &[u8] = &[1, 2, 3];
2621 obj.patch_map_data(HashMap::from([
2622 ("my_config", (test_data, true)),
2623 ("optional_variable", (test_data, false)),
2624 ]))
2625 .unwrap();
2626
2627 let map = obj.maps.get(".rodata").unwrap();
2628 assert_eq!(test_data, map.data());
2629 }
2630
2631 #[test]
2632 fn test_parse_btf_map_section() {
2633 let mut obj = fake_obj();
2634 fake_sym(&mut obj, 0, 0, "map_1", 0);
2635 fake_sym(&mut obj, 0, 0, "map_2", 0);
2636 #[cfg(target_endian = "little")]
2640 let data: &[u8] = &[
2641 0x9F, 0xEB, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x01,
2642 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0xCC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2643 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2644 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
2645 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00,
2646 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
2647 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2648 0x00, 0x02, 0x06, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
2649 0x07, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00,
2650 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
2651 0x09, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0A, 0x00,
2652 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
2653 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0C, 0x00,
2654 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
2655 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2656 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00,
2657 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x05, 0x00,
2658 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
2659 0x80, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xC0, 0x00,
2660 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x0D, 0x00, 0x00, 0x00,
2661 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x20, 0x00,
2662 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2663 0x4A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x4E, 0x00,
2664 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
2665 0x0B, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
2666 0x00, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2667 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
2668 0x00, 0x0D, 0x02, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
2669 0x70, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0C, 0x12, 0x00, 0x00, 0x00, 0xB0, 0x01,
2670 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01,
2671 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00,
2672 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xB5, 0x01, 0x00, 0x00,
2673 0x00, 0x00, 0x00, 0x0E, 0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xBE, 0x01,
2674 0x00, 0x00, 0x02, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
2675 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
2676 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xC4, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0F,
2677 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
2678 0x00, 0x00, 0x00, 0x69, 0x6E, 0x74, 0x00, 0x5F, 0x5F, 0x41, 0x52, 0x52, 0x41, 0x59,
2679 0x5F, 0x53, 0x49, 0x5A, 0x45, 0x5F, 0x54, 0x59, 0x50, 0x45, 0x5F, 0x5F, 0x00, 0x5F,
2680 0x5F, 0x75, 0x33, 0x32, 0x00, 0x75, 0x6E, 0x73, 0x69, 0x67, 0x6E, 0x65, 0x64, 0x20,
2681 0x69, 0x6E, 0x74, 0x00, 0x5F, 0x5F, 0x75, 0x36, 0x34, 0x00, 0x75, 0x6E, 0x73, 0x69,
2682 0x67, 0x6E, 0x65, 0x64, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x6C, 0x6F, 0x6E, 0x67,
2683 0x00, 0x74, 0x79, 0x70, 0x65, 0x00, 0x6B, 0x65, 0x79, 0x00, 0x76, 0x61, 0x6C, 0x75,
2684 0x65, 0x00, 0x6D, 0x61, 0x78, 0x5F, 0x65, 0x6E, 0x74, 0x72, 0x69, 0x65, 0x73, 0x00,
2685 0x6D, 0x61, 0x70, 0x5F, 0x31, 0x00, 0x6D, 0x61, 0x70, 0x5F, 0x32, 0x00, 0x63, 0x74,
2686 0x78, 0x00, 0x62, 0x70, 0x66, 0x5F, 0x70, 0x72, 0x6F, 0x67, 0x00, 0x74, 0x72, 0x61,
2687 0x63, 0x65, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x00, 0x2F, 0x76, 0x61, 0x72, 0x2F, 0x68,
2688 0x6F, 0x6D, 0x65, 0x2F, 0x64, 0x61, 0x76, 0x65, 0x2F, 0x64, 0x65, 0x76, 0x2F, 0x61,
2689 0x79, 0x61, 0x2D, 0x72, 0x73, 0x2F, 0x61, 0x79, 0x61, 0x2F, 0x74, 0x65, 0x73, 0x74,
2690 0x2F, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2D, 0x65,
2691 0x62, 0x70, 0x66, 0x2F, 0x73, 0x72, 0x63, 0x2F, 0x62, 0x70, 0x66, 0x2F, 0x6D, 0x75,
2692 0x6C, 0x74, 0x69, 0x6D, 0x61, 0x70, 0x2D, 0x62, 0x74, 0x66, 0x2E, 0x62, 0x70, 0x66,
2693 0x2E, 0x63, 0x00, 0x69, 0x6E, 0x74, 0x20, 0x62, 0x70, 0x66, 0x5F, 0x70, 0x72, 0x6F,
2694 0x67, 0x28, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x2A, 0x63, 0x74, 0x78, 0x29, 0x00, 0x09,
2695 0x5F, 0x5F, 0x75, 0x33, 0x32, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x3D, 0x20, 0x30, 0x3B,
2696 0x00, 0x09, 0x5F, 0x5F, 0x75, 0x36, 0x34, 0x20, 0x74, 0x77, 0x65, 0x6E, 0x74, 0x79,
2697 0x5F, 0x66, 0x6F, 0x75, 0x72, 0x20, 0x3D, 0x20, 0x32, 0x34, 0x3B, 0x00, 0x09, 0x5F,
2698 0x5F, 0x75, 0x36, 0x34, 0x20, 0x66, 0x6F, 0x72, 0x74, 0x79, 0x5F, 0x74, 0x77, 0x6F,
2699 0x20, 0x3D, 0x20, 0x34, 0x32, 0x3B, 0x00, 0x20, 0x20, 0x20, 0x20, 0x62, 0x70, 0x66,
2700 0x5F, 0x6D, 0x61, 0x70, 0x5F, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5F, 0x65, 0x6C,
2701 0x65, 0x6D, 0x28, 0x26, 0x6D, 0x61, 0x70, 0x5F, 0x31, 0x2C, 0x20, 0x26, 0x6B, 0x65,
2702 0x79, 0x2C, 0x20, 0x26, 0x74, 0x77, 0x65, 0x6E, 0x74, 0x79, 0x5F, 0x66, 0x6F, 0x75,
2703 0x72, 0x2C, 0x20, 0x42, 0x50, 0x46, 0x5F, 0x41, 0x4E, 0x59, 0x29, 0x3B, 0x00, 0x20,
2704 0x20, 0x20, 0x20, 0x62, 0x70, 0x66, 0x5F, 0x6D, 0x61, 0x70, 0x5F, 0x75, 0x70, 0x64,
2705 0x61, 0x74, 0x65, 0x5F, 0x65, 0x6C, 0x65, 0x6D, 0x28, 0x26, 0x6D, 0x61, 0x70, 0x5F,
2706 0x32, 0x2C, 0x20, 0x26, 0x6B, 0x65, 0x79, 0x2C, 0x20, 0x26, 0x66, 0x6F, 0x72, 0x74,
2707 0x79, 0x5F, 0x74, 0x77, 0x6F, 0x2C, 0x20, 0x42, 0x50, 0x46, 0x5F, 0x41, 0x4E, 0x59,
2708 0x29, 0x3B, 0x00, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x30, 0x3B, 0x00,
2709 0x63, 0x68, 0x61, 0x72, 0x00, 0x5F, 0x6C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, 0x00,
2710 0x2E, 0x6D, 0x61, 0x70, 0x73, 0x00, 0x6C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, 0x00,
2711 ];
2712 #[cfg(target_endian = "big")]
2713 let data: &[u8] = &[
2714 0xEB, 0x9F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2715 0x01, 0xF0, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x00, 0x00, 0x00,
2716 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
2717 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
2718 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
2719 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00,
2720 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
2721 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x19, 0x08, 0x00, 0x00, 0x00,
2722 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
2723 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
2724 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
2725 0x00, 0x0A, 0x00, 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
2726 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
2727 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2728 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
2729 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x45,
2730 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00,
2731 0x00, 0x05, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x08,
2732 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00,
2733 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D,
2734 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00,
2735 0x00, 0x20, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
2736 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
2737 0x00, 0x4E, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x54,
2738 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x66, 0x0E, 0x00,
2739 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
2740 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00,
2741 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x11,
2742 0x00, 0x00, 0x00, 0x70, 0x0C, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
2743 0x01, 0xB0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x08,
2744 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2745 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0xB5,
2746 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
2747 0x01, 0xBE, 0x0F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E,
2748 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
2749 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0xC4, 0x0F, 0x00, 0x00, 0x01,
2750 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2751 0x00, 0x04, 0x00, 0x69, 0x6E, 0x74, 0x00, 0x5F, 0x5F, 0x41, 0x52, 0x52, 0x41, 0x59,
2752 0x5F, 0x53, 0x49, 0x5A, 0x45, 0x5F, 0x54, 0x59, 0x50, 0x45, 0x5F, 0x5F, 0x00, 0x5F,
2753 0x5F, 0x75, 0x33, 0x32, 0x00, 0x75, 0x6E, 0x73, 0x69, 0x67, 0x6E, 0x65, 0x64, 0x20,
2754 0x69, 0x6E, 0x74, 0x00, 0x5F, 0x5F, 0x75, 0x36, 0x34, 0x00, 0x75, 0x6E, 0x73, 0x69,
2755 0x67, 0x6E, 0x65, 0x64, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x6C, 0x6F, 0x6E, 0x67,
2756 0x00, 0x74, 0x79, 0x70, 0x65, 0x00, 0x6B, 0x65, 0x79, 0x00, 0x76, 0x61, 0x6C, 0x75,
2757 0x65, 0x00, 0x6D, 0x61, 0x78, 0x5F, 0x65, 0x6E, 0x74, 0x72, 0x69, 0x65, 0x73, 0x00,
2758 0x6D, 0x61, 0x70, 0x5F, 0x31, 0x00, 0x6D, 0x61, 0x70, 0x5F, 0x32, 0x00, 0x63, 0x74,
2759 0x78, 0x00, 0x62, 0x70, 0x66, 0x5F, 0x70, 0x72, 0x6F, 0x67, 0x00, 0x74, 0x72, 0x61,
2760 0x63, 0x65, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x00, 0x2F, 0x76, 0x61, 0x72, 0x2F, 0x68,
2761 0x6F, 0x6D, 0x65, 0x2F, 0x64, 0x61, 0x76, 0x65, 0x2F, 0x64, 0x65, 0x76, 0x2F, 0x61,
2762 0x79, 0x61, 0x2D, 0x72, 0x73, 0x2F, 0x61, 0x79, 0x61, 0x2F, 0x74, 0x65, 0x73, 0x74,
2763 0x2F, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2D, 0x65,
2764 0x62, 0x70, 0x66, 0x2F, 0x73, 0x72, 0x63, 0x2F, 0x62, 0x70, 0x66, 0x2F, 0x6D, 0x75,
2765 0x6C, 0x74, 0x69, 0x6D, 0x61, 0x70, 0x2D, 0x62, 0x74, 0x66, 0x2E, 0x62, 0x70, 0x66,
2766 0x2E, 0x63, 0x00, 0x69, 0x6E, 0x74, 0x20, 0x62, 0x70, 0x66, 0x5F, 0x70, 0x72, 0x6F,
2767 0x67, 0x28, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x2A, 0x63, 0x74, 0x78, 0x29, 0x00, 0x09,
2768 0x5F, 0x5F, 0x75, 0x33, 0x32, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x3D, 0x20, 0x30, 0x3B,
2769 0x00, 0x09, 0x5F, 0x5F, 0x75, 0x36, 0x34, 0x20, 0x74, 0x77, 0x65, 0x6E, 0x74, 0x79,
2770 0x5F, 0x66, 0x6F, 0x75, 0x72, 0x20, 0x3D, 0x20, 0x32, 0x34, 0x3B, 0x00, 0x09, 0x5F,
2771 0x5F, 0x75, 0x36, 0x34, 0x20, 0x66, 0x6F, 0x72, 0x74, 0x79, 0x5F, 0x74, 0x77, 0x6F,
2772 0x20, 0x3D, 0x20, 0x34, 0x32, 0x3B, 0x00, 0x20, 0x20, 0x20, 0x20, 0x62, 0x70, 0x66,
2773 0x5F, 0x6D, 0x61, 0x70, 0x5F, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5F, 0x65, 0x6C,
2774 0x65, 0x6D, 0x28, 0x26, 0x6D, 0x61, 0x70, 0x5F, 0x31, 0x2C, 0x20, 0x26, 0x6B, 0x65,
2775 0x79, 0x2C, 0x20, 0x26, 0x74, 0x77, 0x65, 0x6E, 0x74, 0x79, 0x5F, 0x66, 0x6F, 0x75,
2776 0x72, 0x2C, 0x20, 0x42, 0x50, 0x46, 0x5F, 0x41, 0x4E, 0x59, 0x29, 0x3B, 0x00, 0x20,
2777 0x20, 0x20, 0x20, 0x62, 0x70, 0x66, 0x5F, 0x6D, 0x61, 0x70, 0x5F, 0x75, 0x70, 0x64,
2778 0x61, 0x74, 0x65, 0x5F, 0x65, 0x6C, 0x65, 0x6D, 0x28, 0x26, 0x6D, 0x61, 0x70, 0x5F,
2779 0x32, 0x2C, 0x20, 0x26, 0x6B, 0x65, 0x79, 0x2C, 0x20, 0x26, 0x66, 0x6F, 0x72, 0x74,
2780 0x79, 0x5F, 0x74, 0x77, 0x6F, 0x2C, 0x20, 0x42, 0x50, 0x46, 0x5F, 0x41, 0x4E, 0x59,
2781 0x29, 0x3B, 0x00, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x30, 0x3B, 0x00,
2782 0x63, 0x68, 0x61, 0x72, 0x00, 0x5F, 0x6C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, 0x00,
2783 0x2E, 0x6D, 0x61, 0x70, 0x73, 0x00, 0x6C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, 0x00,
2784 ];
2785
2786 let btf_section = fake_section(EbpfSectionKind::Btf, ".BTF", data, None);
2787 obj.parse_section(btf_section).unwrap();
2788
2789 let map_section = fake_section(EbpfSectionKind::BtfMaps, ".maps", &[], None);
2790 obj.parse_section(map_section).unwrap();
2791
2792 let map = obj.maps.get("map_1").unwrap();
2793 assert_matches!(map, Map::Btf(m) => {
2794 assert_eq!(m.def.key_size, 4);
2795 assert_eq!(m.def.value_size, 8);
2796 assert_eq!(m.def.max_entries, 1);
2797 });
2798 }
2799}