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