aya_obj/
obj.rs

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