aya_obj/
obj.rs

1//! Object file loading, parsing, and relocation.
2
3use 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/// Features implements BPF and BTF feature detection
39#[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    /// Returns whether BPF program names and map names are supported.
77    ///
78    /// Although the feature probe performs the check for program name, we can use this to also
79    /// detect if map name is supported since they were both introduced in the same commit.
80    pub fn bpf_name(&self) -> bool {
81        self.bpf_name
82    }
83
84    /// Returns whether the bpf_probe_read_kernel helper is supported.
85    pub fn bpf_probe_read_kernel(&self) -> bool {
86        self.bpf_probe_read_kernel
87    }
88
89    /// Returns whether bpf_links are supported for Kprobes/Uprobes/Tracepoints.
90    pub fn bpf_perf_link(&self) -> bool {
91        self.bpf_perf_link
92    }
93
94    /// Returns whether BPF program global data is supported.
95    pub fn bpf_global_data(&self) -> bool {
96        self.bpf_global_data
97    }
98
99    /// Returns whether BPF program cookie is supported.
100    pub fn bpf_cookie(&self) -> bool {
101        self.bpf_cookie
102    }
103
104    /// Returns whether XDP CPU Maps support chained program IDs.
105    pub fn cpumap_prog_id(&self) -> bool {
106        self.cpumap_prog_id
107    }
108
109    /// Returns whether XDP Device Maps support chained program IDs.
110    pub fn devmap_prog_id(&self) -> bool {
111        self.devmap_prog_id
112    }
113
114    /// If BTF is supported, returns which BTF features are supported.
115    pub fn btf(&self) -> Option<&BtfFeatures> {
116        self.btf.as_ref()
117    }
118}
119
120/// The loaded object file representation
121#[derive(Clone, Debug)]
122pub struct Object {
123    /// The endianness
124    pub endianness: Endianness,
125    /// Program license
126    pub license: CString,
127    /// Kernel version
128    pub kernel_version: Option<u32>,
129    /// Program BTF
130    pub btf: Option<Btf>,
131    /// Program BTF.ext
132    pub btf_ext: Option<BtfExt>,
133    /// Referenced maps
134    pub maps: HashMap<String, Map>,
135    /// A hash map of programs, using the program names parsed
136    /// in [ProgramSection]s as keys.
137    pub programs: HashMap<String, Program>,
138    /// Functions
139    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    // symbol_offset_by_name caches symbols that could be referenced from a
145    // BTF VAR type so the offsets can be fixed up
146    pub(crate) symbol_offset_by_name: HashMap<String, u64>,
147}
148
149/// An eBPF program
150#[derive(Debug, Clone)]
151pub struct Program {
152    /// The license
153    pub license: CString,
154    /// The kernel version
155    pub kernel_version: Option<u32>,
156    /// The section containing the program
157    pub section: ProgramSection,
158    /// The section index of the program
159    pub section_index: usize,
160    /// The address of the program
161    pub address: u64,
162}
163
164impl Program {
165    /// The key used by [Object::functions]
166    pub fn function_key(&self) -> (usize, u64) {
167        (self.section_index, self.address)
168    }
169}
170
171/// An eBPF function
172#[derive(Debug, Clone)]
173pub struct Function {
174    /// The address
175    pub address: u64,
176    /// The function name
177    pub name: String,
178    /// The section index
179    pub section_index: SectionIndex,
180    /// The section offset
181    pub section_offset: usize,
182    /// The eBPF byte code instructions
183    pub instructions: Vec<bpf_insn>,
184    /// The function info
185    pub func_info: FuncSecInfo,
186    /// The line info
187    pub line_info: LineSecInfo,
188    /// Function info record size
189    pub func_info_rec_size: usize,
190    /// Line info record size
191    pub line_info_rec_size: usize,
192}
193
194/// Section types containing eBPF programs
195///
196/// # Section Name Parsing
197///
198/// Section types are parsed from the section name strings.
199///
200/// In order for Aya to treat a section as a [ProgramSection],
201/// there are a few requirements:
202/// - The section must be an executable code section.
203/// - The section name must conform to [Program Types and ELF Sections].
204///
205/// [Program Types and ELF Sections]: https://docs.kernel.org/bpf/libbpf/program_types.html
206///
207/// # Unsupported Sections
208///
209/// Currently, the following section names are not supported yet:
210/// - `flow_dissector`: `BPF_PROG_TYPE_FLOW_DISSECTOR`
211/// - `ksyscall+` or `kretsyscall+`
212/// - `usdt+`
213/// - `kprobe.multi+` or `kretprobe.multi+`: `BPF_TRACE_KPROBE_MULTI`
214/// - `lsm_cgroup+`
215/// - `lwt_in`, `lwt_out`, `lwt_seg6local`, `lwt_xmit`
216/// - `raw_tp.w+`, `raw_tracepoint.w+`
217/// - `action`
218/// - `sk_reuseport/migrate`, `sk_reuseport`
219/// - `syscall`
220/// - `struct_ops+`
221/// - `fmod_ret+`, `fmod_ret.s+`
222/// - `iter+`, `iter.s+`
223#[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        // parse the common case, eg "xdp/program_name" or
286        // "sk_skb/stream_verdict/program_name"
287        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    /// Parses the binary data as an object file into an [Object]
443    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(&section)?.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(&section)?.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        // .BTF and .BTF.ext sections must be parsed first
492        // as they're required to prepare function and line information
493        // when parsing program sections
494        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    /// Returns true if this object contains CO-RE relocations.
533    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    /// Patches map data
540    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                    // assumption: there is only one map created per section where we're trying to
564                    // patch data. this assumption holds true for the .rodata section at least
565                    .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(&section.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            // Here we get both ::Label (LBB*) and ::Text symbols, and we only want the latter.
618            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(&section.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, &section, 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                        &section.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(&section.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                    // each btf_var_secinfo contains a map
767                    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    // Parses multiple map definition contained in a single `maps` section (which is
791    // different from `.maps` which is used for BTF). We can tell where each map is
792    // based on the symbol table.
793    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        // each symbol in the section is a separate map
801        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 = &section.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(&section)?);
841            }
842            EbpfSectionKind::Text => self.parse_text_section(section)?,
843            EbpfSectionKind::Btf => self.parse_btf(&section)?,
844            EbpfSectionKind::BtfExt => self.parse_btf_ext(&section)?,
845            EbpfSectionKind::BtfMaps => self.parse_btf_maps(&section)?,
846            EbpfSectionKind::Maps => {
847                // take out self.maps so we can borrow the iterator below
848                // without cloning or collecting
849                let mut maps = mem::take(&mut self.maps);
850
851                // extract the symbols for the .maps section, we'll need them
852                // during parsing
853                let symbols = self
854                    .symbols_by_section
855                    .get(&section.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, &section, symbols);
862
863                // put the maps back
864                self.maps = maps;
865
866                res?
867            }
868            EbpfSectionKind::Program => {
869                self.parse_programs(&section)?;
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    /// Sanitize BPF functions.
888    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/// Errors caught during parsing the object file
933#[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 parsing BTF object
940    #[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    /// No BTF parsed for object
999    #[error("no BTF parsed for object")]
1000    NoBTF,
1001}
1002
1003/// Invalid bindings to the bpf type from the parsed/received value.
1004pub struct InvalidTypeBinding<T> {
1005    /// The value parsed/received.
1006    pub value: T,
1007}
1008
1009/// The kind of an ELF section.
1010#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1011pub enum EbpfSectionKind {
1012    /// Undefined
1013    Undefined,
1014    /// `maps`
1015    Maps,
1016    /// `.maps`
1017    BtfMaps,
1018    /// A program section
1019    Program,
1020    /// `.data`
1021    Data,
1022    /// `.rodata`
1023    Rodata,
1024    /// `.bss`
1025    Bss,
1026    /// `.text`
1027    Text,
1028    /// `.BTF`
1029    Btf,
1030    /// `.BTF.ext`
1031    BtfExt,
1032    /// `license`
1033    License,
1034    /// `version`
1035    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
1162// Gets an integer value from a BTF map defintion K/V pair.
1163// type_id should be a PTR to an ARRAY.
1164// the value is encoded in the array nr_elems field.
1165fn 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
1185// Parsed '.bss' '.data' and '.rodata' sections. These sections are arrays of
1186// bytes and are relocated based on their section index.
1187fn 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                // We need to use section.size here since
1194                // .bss will always have data.len() == 0
1195                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        // Data maps don't require symbols to be relocated
1223        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    // In aya-ebpf, the BTF map definition types are not used directly in the
1271    // map variables. Instead, they are wrapped in two nested types:
1272    //
1273    // * A struct representing the map type (e.g., `Array`, `HashMap`) that
1274    //   provides methods for interacting with the map type (e.g.
1275    //   `HashMap::get`, `RingBuf::reserve`).
1276    //   * It has a single field with name `__0`.
1277    // * An `UnsafeCell`, which informs the Rust compiler that the type is
1278    //   thread-safe and can be safely mutated even as a global variable. The
1279    //   kernel guarantees map operation safety.
1280    //   * It has a single field with name `value`.
1281    //
1282    // Therefore, the traversal to the actual map definition looks like:
1283    //
1284    //   HashMap -> __0 -> value
1285    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            // If the first wrapper level is missing, use the original struct.
1303            _ => {
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
1368/// Parses a [bpf_map_info] into a [Map].
1369pub 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
1405/// Copies a block of eBPF instructions
1406pub 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        // Safety: This is for testing only
1522        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        // throw in some padding
1851        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        // generated from:
2689        // objcopy --dump-section .BTF=test.btf ./target/bpfel-unknown-none/debug/multimap-btf.bpf.o
2690        // hexdump -v  -e '7/1 "0x%02X, " 1/1  " 0x%02X,\n"' test.btf
2691        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}