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