1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674 |
- //! Object file loading, parsing, and relocation.
- use alloc::{
- borrow::ToOwned,
- collections::BTreeMap,
- ffi::CString,
- string::{String, ToString},
- vec::Vec,
- };
- use core::{ffi::CStr, mem, ptr, slice::from_raw_parts_mut, str::FromStr};
- use log::debug;
- use object::{
- read::{Object as ElfObject, ObjectSection, Section as ObjSection},
- Endianness, ObjectSymbol, ObjectSymbolTable, RelocationTarget, SectionIndex, SectionKind,
- SymbolKind,
- };
- #[cfg(not(feature = "std"))]
- use crate::std;
- use crate::{
- btf::{
- Array, Btf, BtfError, BtfExt, BtfFeatures, BtfType, DataSecEntry, FuncSecInfo, LineSecInfo,
- },
- generated::{
- bpf_insn, bpf_map_info, bpf_map_type::BPF_MAP_TYPE_ARRAY, BPF_CALL, BPF_F_RDONLY_PROG,
- BPF_JMP, BPF_K,
- },
- maps::{bpf_map_def, BtfMap, BtfMapDef, LegacyMap, Map, PinningType, MINIMUM_MAP_SIZE},
- programs::{
- CgroupSockAddrAttachType, CgroupSockAttachType, CgroupSockoptAttachType, XdpAttachType,
- },
- relocation::*,
- util::HashMap,
- };
- const KERNEL_VERSION_ANY: u32 = 0xFFFF_FFFE;
- /// Features implements BPF and BTF feature detection
- #[derive(Default, Debug)]
- #[allow(missing_docs)]
- pub struct Features {
- bpf_name: bool,
- bpf_probe_read_kernel: bool,
- bpf_perf_link: bool,
- bpf_global_data: bool,
- bpf_cookie: bool,
- cpumap_prog_id: bool,
- devmap_prog_id: bool,
- btf: Option<BtfFeatures>,
- }
- impl Features {
- #[doc(hidden)]
- #[allow(clippy::too_many_arguments)]
- pub fn new(
- bpf_name: bool,
- bpf_probe_read_kernel: bool,
- bpf_perf_link: bool,
- bpf_global_data: bool,
- bpf_cookie: bool,
- cpumap_prog_id: bool,
- devmap_prog_id: bool,
- btf: Option<BtfFeatures>,
- ) -> Self {
- Self {
- bpf_name,
- bpf_probe_read_kernel,
- bpf_perf_link,
- bpf_global_data,
- bpf_cookie,
- cpumap_prog_id,
- devmap_prog_id,
- btf,
- }
- }
- /// Returns whether BPF program names are supported.
- pub fn bpf_name(&self) -> bool {
- self.bpf_name
- }
- /// Returns whether the bpf_probe_read_kernel helper is supported.
- pub fn bpf_probe_read_kernel(&self) -> bool {
- self.bpf_probe_read_kernel
- }
- /// Returns whether bpf_links are supported for Kprobes/Uprobes/Tracepoints.
- pub fn bpf_perf_link(&self) -> bool {
- self.bpf_perf_link
- }
- /// Returns whether BPF program global data is supported.
- pub fn bpf_global_data(&self) -> bool {
- self.bpf_global_data
- }
- /// Returns whether BPF program cookie is supported.
- pub fn bpf_cookie(&self) -> bool {
- self.bpf_cookie
- }
- /// Returns whether XDP CPU Maps support chained program IDs.
- pub fn cpumap_prog_id(&self) -> bool {
- self.cpumap_prog_id
- }
- /// Returns whether XDP Device Maps support chained program IDs.
- pub fn devmap_prog_id(&self) -> bool {
- self.devmap_prog_id
- }
- /// If BTF is supported, returns which BTF features are supported.
- pub fn btf(&self) -> Option<&BtfFeatures> {
- self.btf.as_ref()
- }
- }
- /// The loaded object file representation
- #[derive(Clone, Debug)]
- pub struct Object {
- /// The endianness
- pub endianness: Endianness,
- /// Program license
- pub license: CString,
- /// Kernel version
- pub kernel_version: Option<u32>,
- /// Program BTF
- pub btf: Option<Btf>,
- /// Program BTF.ext
- pub btf_ext: Option<BtfExt>,
- /// Referenced maps
- pub maps: HashMap<String, Map>,
- /// A hash map of programs, using the program names parsed
- /// in [ProgramSection]s as keys.
- pub programs: HashMap<String, Program>,
- /// Functions
- pub functions: BTreeMap<(usize, u64), Function>,
- pub(crate) relocations: HashMap<SectionIndex, HashMap<u64, Relocation>>,
- pub(crate) symbol_table: HashMap<usize, Symbol>,
- pub(crate) symbols_by_section: HashMap<SectionIndex, Vec<usize>>,
- pub(crate) section_infos: HashMap<String, (SectionIndex, u64)>,
- // symbol_offset_by_name caches symbols that could be referenced from a
- // BTF VAR type so the offsets can be fixed up
- pub(crate) symbol_offset_by_name: HashMap<String, u64>,
- }
- /// An eBPF program
- #[derive(Debug, Clone)]
- pub struct Program {
- /// The license
- pub license: CString,
- /// The kernel version
- pub kernel_version: Option<u32>,
- /// The section containing the program
- pub section: ProgramSection,
- /// The section index of the program
- pub section_index: usize,
- /// The address of the program
- pub address: u64,
- }
- impl Program {
- /// The key used by [Object::functions]
- pub fn function_key(&self) -> (usize, u64) {
- (self.section_index, self.address)
- }
- }
- /// An eBPF function
- #[derive(Debug, Clone)]
- pub struct Function {
- /// The address
- pub address: u64,
- /// The function name
- pub name: String,
- /// The section index
- pub section_index: SectionIndex,
- /// The section offset
- pub section_offset: usize,
- /// The eBPF byte code instructions
- pub instructions: Vec<bpf_insn>,
- /// The function info
- pub func_info: FuncSecInfo,
- /// The line info
- pub line_info: LineSecInfo,
- /// Function info record size
- pub func_info_rec_size: usize,
- /// Line info record size
- pub line_info_rec_size: usize,
- }
- /// Section types containing eBPF programs
- ///
- /// # Section Name Parsing
- ///
- /// Section types are parsed from the section name strings.
- ///
- /// In order for Aya to treat a section as a [ProgramSection],
- /// there are a few requirements:
- /// - The section must be an executable code section.
- /// - The section name must conform to [Program Types and ELF Sections].
- ///
- /// [Program Types and ELF Sections]: https://docs.kernel.org/bpf/libbpf/program_types.html
- ///
- /// # Unsupported Sections
- ///
- /// Currently, the following section names are not supported yet:
- /// - `flow_dissector`: `BPF_PROG_TYPE_FLOW_DISSECTOR`
- /// - `ksyscall+` or `kretsyscall+`
- /// - `usdt+`
- /// - `kprobe.multi+` or `kretprobe.multi+`: `BPF_TRACE_KPROBE_MULTI`
- /// - `lsm_cgroup+`
- /// - `lwt_in`, `lwt_out`, `lwt_seg6local`, `lwt_xmit`
- /// - `raw_tp.w+`, `raw_tracepoint.w+`
- /// - `action`
- /// - `sk_reuseport/migrate`, `sk_reuseport`
- /// - `syscall`
- /// - `struct_ops+`
- /// - `fmod_ret+`, `fmod_ret.s+`
- /// - `iter+`, `iter.s+`
- #[derive(Debug, Clone)]
- #[allow(missing_docs)]
- pub enum ProgramSection {
- KRetProbe,
- KProbe,
- UProbe {
- sleepable: bool,
- },
- URetProbe {
- sleepable: bool,
- },
- TracePoint,
- SocketFilter,
- Xdp {
- frags: bool,
- attach_type: XdpAttachType,
- },
- SkMsg,
- SkSkbStreamParser,
- SkSkbStreamVerdict,
- SockOps,
- SchedClassifier,
- CgroupSkb,
- CgroupSkbIngress,
- CgroupSkbEgress,
- CgroupSockAddr {
- attach_type: CgroupSockAddrAttachType,
- },
- CgroupSysctl,
- CgroupSockopt {
- attach_type: CgroupSockoptAttachType,
- },
- LircMode2,
- PerfEvent,
- RawTracePoint,
- Lsm {
- sleepable: bool,
- },
- BtfTracePoint,
- FEntry {
- sleepable: bool,
- },
- FExit {
- sleepable: bool,
- },
- Extension,
- SkLookup,
- CgroupSock {
- attach_type: CgroupSockAttachType,
- },
- CgroupDevice,
- }
- impl FromStr for ProgramSection {
- type Err = ParseError;
- fn from_str(section: &str) -> Result<ProgramSection, ParseError> {
- use ProgramSection::*;
- // parse the common case, eg "xdp/program_name" or
- // "sk_skb/stream_verdict/program_name"
- let mut pieces = section.split('/');
- let mut next = || {
- pieces
- .next()
- .ok_or_else(|| ParseError::InvalidProgramSection {
- section: section.to_owned(),
- })
- };
- let kind = next()?;
- Ok(match kind {
- "kprobe" => KProbe,
- "kretprobe" => KRetProbe,
- "uprobe" => UProbe { sleepable: false },
- "uprobe.s" => UProbe { sleepable: true },
- "uretprobe" => URetProbe { sleepable: false },
- "uretprobe.s" => URetProbe { sleepable: true },
- "xdp" | "xdp.frags" => Xdp {
- frags: kind == "xdp.frags",
- attach_type: match pieces.next() {
- None => XdpAttachType::Interface,
- Some("cpumap") => XdpAttachType::CpuMap,
- Some("devmap") => XdpAttachType::DevMap,
- Some(_) => {
- return Err(ParseError::InvalidProgramSection {
- section: section.to_owned(),
- })
- }
- },
- },
- "tp_btf" => BtfTracePoint,
- "tracepoint" | "tp" => TracePoint,
- "socket" => SocketFilter,
- "sk_msg" => SkMsg,
- "sk_skb" => {
- let name = next()?;
- match name {
- "stream_parser" => SkSkbStreamParser,
- "stream_verdict" => SkSkbStreamVerdict,
- _ => {
- return Err(ParseError::InvalidProgramSection {
- section: section.to_owned(),
- })
- }
- }
- }
- "sockops" => SockOps,
- "classifier" => SchedClassifier,
- "cgroup_skb" => {
- let name = next()?;
- match name {
- "ingress" => CgroupSkbIngress,
- "egress" => CgroupSkbEgress,
- _ => {
- return Err(ParseError::InvalidProgramSection {
- section: section.to_owned(),
- })
- }
- }
- }
- "cgroup" => {
- let name = next()?;
- match name {
- "skb" => CgroupSkb,
- "sysctl" => CgroupSysctl,
- "dev" => CgroupDevice,
- "getsockopt" => CgroupSockopt {
- attach_type: CgroupSockoptAttachType::Get,
- },
- "setsockopt" => CgroupSockopt {
- attach_type: CgroupSockoptAttachType::Set,
- },
- "sock" => CgroupSock {
- attach_type: CgroupSockAttachType::default(),
- },
- "post_bind4" => CgroupSock {
- attach_type: CgroupSockAttachType::PostBind4,
- },
- "post_bind6" => CgroupSock {
- attach_type: CgroupSockAttachType::PostBind6,
- },
- "sock_create" => CgroupSock {
- attach_type: CgroupSockAttachType::SockCreate,
- },
- "sock_release" => CgroupSock {
- attach_type: CgroupSockAttachType::SockRelease,
- },
- "bind4" => CgroupSockAddr {
- attach_type: CgroupSockAddrAttachType::Bind4,
- },
- "bind6" => CgroupSockAddr {
- attach_type: CgroupSockAddrAttachType::Bind6,
- },
- "connect4" => CgroupSockAddr {
- attach_type: CgroupSockAddrAttachType::Connect4,
- },
- "connect6" => CgroupSockAddr {
- attach_type: CgroupSockAddrAttachType::Connect6,
- },
- "getpeername4" => CgroupSockAddr {
- attach_type: CgroupSockAddrAttachType::GetPeerName4,
- },
- "getpeername6" => CgroupSockAddr {
- attach_type: CgroupSockAddrAttachType::GetPeerName6,
- },
- "getsockname4" => CgroupSockAddr {
- attach_type: CgroupSockAddrAttachType::GetSockName4,
- },
- "getsockname6" => CgroupSockAddr {
- attach_type: CgroupSockAddrAttachType::GetSockName6,
- },
- "sendmsg4" => CgroupSockAddr {
- attach_type: CgroupSockAddrAttachType::UDPSendMsg4,
- },
- "sendmsg6" => CgroupSockAddr {
- attach_type: CgroupSockAddrAttachType::UDPSendMsg6,
- },
- "recvmsg4" => CgroupSockAddr {
- attach_type: CgroupSockAddrAttachType::UDPRecvMsg4,
- },
- "recvmsg6" => CgroupSockAddr {
- attach_type: CgroupSockAddrAttachType::UDPRecvMsg6,
- },
- _ => {
- return Err(ParseError::InvalidProgramSection {
- section: section.to_owned(),
- });
- }
- }
- }
- "lirc_mode2" => LircMode2,
- "perf_event" => PerfEvent,
- "raw_tp" | "raw_tracepoint" => RawTracePoint,
- "lsm" => Lsm { sleepable: false },
- "lsm.s" => Lsm { sleepable: true },
- "fentry" => FEntry { sleepable: false },
- "fentry.s" => FEntry { sleepable: true },
- "fexit" => FExit { sleepable: false },
- "fexit.s" => FExit { sleepable: true },
- "freplace" => Extension,
- "sk_lookup" => SkLookup,
- _ => {
- return Err(ParseError::InvalidProgramSection {
- section: section.to_owned(),
- })
- }
- })
- }
- }
- impl Object {
- /// Parses the binary data as an object file into an [Object]
- pub fn parse(data: &[u8]) -> Result<Object, ParseError> {
- let obj = object::read::File::parse(data).map_err(ParseError::ElfError)?;
- let endianness = obj.endianness();
- let license = if let Some(section) = obj.section_by_name("license") {
- parse_license(Section::try_from(§ion)?.data)?
- } else {
- CString::new("GPL").unwrap()
- };
- let kernel_version = if let Some(section) = obj.section_by_name("version") {
- parse_version(Section::try_from(§ion)?.data, endianness)?
- } else {
- None
- };
- let mut bpf_obj = Object::new(endianness, license, kernel_version);
- if let Some(symbol_table) = obj.symbol_table() {
- for symbol in symbol_table.symbols() {
- let name = symbol
- .name()
- .ok()
- .map(String::from)
- .ok_or(BtfError::InvalidSymbolName)?;
- let sym = Symbol {
- index: symbol.index().0,
- name: Some(name.clone()),
- section_index: symbol.section().index().map(|i| i.0),
- address: symbol.address(),
- size: symbol.size(),
- is_definition: symbol.is_definition(),
- kind: symbol.kind(),
- };
- bpf_obj.symbol_table.insert(symbol.index().0, sym);
- if let Some(section_idx) = symbol.section().index() {
- bpf_obj
- .symbols_by_section
- .entry(section_idx)
- .or_default()
- .push(symbol.index().0);
- }
- if symbol.is_global() || symbol.kind() == SymbolKind::Data {
- bpf_obj.symbol_offset_by_name.insert(name, symbol.address());
- }
- }
- }
- // .BTF and .BTF.ext sections must be parsed first
- // as they're required to prepare function and line information
- // when parsing program sections
- if let Some(s) = obj.section_by_name(".BTF") {
- bpf_obj.parse_section(Section::try_from(&s)?)?;
- if let Some(s) = obj.section_by_name(".BTF.ext") {
- bpf_obj.parse_section(Section::try_from(&s)?)?;
- }
- }
- for s in obj.sections() {
- if let Ok(name) = s.name() {
- if name == ".BTF" || name == ".BTF.ext" {
- continue;
- }
- }
- bpf_obj.parse_section(Section::try_from(&s)?)?;
- }
- Ok(bpf_obj)
- }
- fn new(endianness: Endianness, license: CString, kernel_version: Option<u32>) -> Object {
- Object {
- endianness,
- license,
- kernel_version,
- btf: None,
- btf_ext: None,
- maps: HashMap::new(),
- programs: HashMap::new(),
- functions: BTreeMap::new(),
- relocations: HashMap::new(),
- symbol_table: HashMap::new(),
- symbols_by_section: HashMap::new(),
- section_infos: HashMap::new(),
- symbol_offset_by_name: HashMap::new(),
- }
- }
- /// Patches map data
- pub fn patch_map_data(
- &mut self,
- globals: HashMap<&str, (&[u8], bool)>,
- ) -> Result<(), ParseError> {
- let symbols: HashMap<String, &Symbol> = self
- .symbol_table
- .iter()
- .filter(|(_, s)| s.name.is_some())
- .map(|(_, s)| (s.name.as_ref().unwrap().clone(), s))
- .collect();
- for (name, (data, must_exist)) in globals {
- if let Some(symbol) = symbols.get(name) {
- if data.len() as u64 != symbol.size {
- return Err(ParseError::InvalidGlobalData {
- name: name.to_string(),
- sym_size: symbol.size,
- data_size: data.len(),
- });
- }
- let (_, map) = self
- .maps
- .iter_mut()
- // assumption: there is only one map created per section where we're trying to
- // patch data. this assumption holds true for the .rodata section at least
- .find(|(_, m)| symbol.section_index == Some(m.section_index()))
- .ok_or_else(|| ParseError::MapNotFound {
- index: symbol.section_index.unwrap_or(0),
- })?;
- let start = symbol.address as usize;
- let end = start + symbol.size as usize;
- if start > end || end > map.data().len() {
- return Err(ParseError::InvalidGlobalData {
- name: name.to_string(),
- sym_size: symbol.size,
- data_size: data.len(),
- });
- }
- map.data_mut().splice(start..end, data.iter().cloned());
- } else if must_exist {
- return Err(ParseError::SymbolNotFound {
- name: name.to_owned(),
- });
- }
- }
- Ok(())
- }
- fn parse_btf(&mut self, section: &Section) -> Result<(), BtfError> {
- self.btf = Some(Btf::parse(section.data, self.endianness)?);
- Ok(())
- }
- fn parse_btf_ext(&mut self, section: &Section) -> Result<(), BtfError> {
- self.btf_ext = Some(BtfExt::parse(
- section.data,
- self.endianness,
- self.btf.as_ref().unwrap(),
- )?);
- Ok(())
- }
- fn parse_programs(&mut self, section: &Section) -> Result<(), ParseError> {
- let program_section = ProgramSection::from_str(section.name)?;
- let syms =
- self.symbols_by_section
- .get(§ion.index)
- .ok_or(ParseError::NoSymbolsForSection {
- section_name: section.name.to_string(),
- })?;
- for symbol_index in syms {
- let symbol = self
- .symbol_table
- .get(symbol_index)
- .expect("all symbols in symbols_by_section are also in symbol_table");
- let Some(name) = symbol.name.as_ref() else {
- continue;
- };
- if name.is_empty() {
- continue;
- }
- let (p, f) =
- self.parse_program(section, program_section.clone(), name.to_string(), symbol)?;
- let key = p.function_key();
- self.programs.insert(f.name.clone(), p);
- self.functions.insert(key, f);
- }
- Ok(())
- }
- fn parse_program(
- &self,
- section: &Section,
- program_section: ProgramSection,
- name: String,
- symbol: &Symbol,
- ) -> Result<(Program, Function), ParseError> {
- let offset = symbol.address as usize - section.address as usize;
- let (func_info, line_info, func_info_rec_size, line_info_rec_size) =
- get_func_and_line_info(self.btf_ext.as_ref(), symbol, section, offset, true);
- let start = symbol.address as usize;
- let end = (symbol.address + symbol.size) as usize;
- let function = Function {
- name: name.to_owned(),
- address: symbol.address,
- section_index: section.index,
- section_offset: start,
- instructions: copy_instructions(§ion.data[start..end])?,
- func_info,
- line_info,
- func_info_rec_size,
- line_info_rec_size,
- };
- Ok((
- Program {
- license: self.license.clone(),
- kernel_version: self.kernel_version,
- section: program_section.clone(),
- section_index: section.index.0,
- address: symbol.address,
- },
- function,
- ))
- }
- fn parse_text_section(&mut self, section: Section) -> Result<(), ParseError> {
- let mut symbols_by_address = HashMap::new();
- for sym in self.symbol_table.values() {
- if sym.is_definition
- && sym.kind == SymbolKind::Text
- && sym.section_index == Some(section.index.0)
- {
- if symbols_by_address.contains_key(&sym.address) {
- return Err(ParseError::SymbolTableConflict {
- section_index: section.index.0,
- address: sym.address,
- });
- }
- symbols_by_address.insert(sym.address, sym);
- }
- }
- let mut offset = 0;
- while offset < section.data.len() {
- let address = section.address + offset as u64;
- let sym = symbols_by_address
- .get(&address)
- .ok_or(ParseError::UnknownSymbol {
- section_index: section.index.0,
- address,
- })?;
- if sym.size == 0 {
- return Err(ParseError::InvalidSymbol {
- index: sym.index,
- name: sym.name.clone(),
- });
- }
- let (func_info, line_info, func_info_rec_size, line_info_rec_size) =
- get_func_and_line_info(self.btf_ext.as_ref(), sym, §ion, offset, false);
- self.functions.insert(
- (section.index.0, sym.address),
- Function {
- address,
- name: sym.name.clone().unwrap(),
- section_index: section.index,
- section_offset: offset,
- instructions: copy_instructions(
- §ion.data[offset..offset + sym.size as usize],
- )?,
- func_info,
- line_info,
- func_info_rec_size,
- line_info_rec_size,
- },
- );
- offset += sym.size as usize;
- }
- if !section.relocations.is_empty() {
- self.relocations.insert(
- section.index,
- section
- .relocations
- .into_iter()
- .map(|rel| (rel.offset, rel))
- .collect(),
- );
- }
- Ok(())
- }
- fn parse_btf_maps(&mut self, section: &Section) -> Result<(), ParseError> {
- if self.btf.is_none() {
- return Err(ParseError::NoBTF);
- }
- let btf = self.btf.as_ref().unwrap();
- let maps: HashMap<&String, usize> = self
- .symbols_by_section
- .get(§ion.index)
- .ok_or(ParseError::NoSymbolsForSection {
- section_name: section.name.to_owned(),
- })?
- .iter()
- .filter_map(|s| {
- let symbol = self.symbol_table.get(s).unwrap();
- symbol.name.as_ref().map(|name| (name, symbol.index))
- })
- .collect();
- for t in btf.types() {
- if let BtfType::DataSec(datasec) = &t {
- let type_name = match btf.type_name(t) {
- Ok(name) => name,
- _ => continue,
- };
- if type_name == section.name {
- // each btf_var_secinfo contains a map
- for info in &datasec.entries {
- let (map_name, def) = parse_btf_map_def(btf, info)?;
- let symbol_index =
- maps.get(&map_name)
- .ok_or_else(|| ParseError::SymbolNotFound {
- name: map_name.to_string(),
- })?;
- self.maps.insert(
- map_name,
- Map::Btf(BtfMap {
- def,
- section_index: section.index.0,
- symbol_index: *symbol_index,
- data: Vec::new(),
- }),
- );
- }
- }
- }
- }
- Ok(())
- }
- // Parses multiple map definition contained in a single `maps` section (which is
- // different from `.maps` which is used for BTF). We can tell where each map is
- // based on the symbol table.
- fn parse_maps_section<'a, I: Iterator<Item = &'a usize>>(
- &self,
- maps: &mut HashMap<String, Map>,
- section: &Section,
- symbols: I,
- ) -> Result<(), ParseError> {
- let mut have_symbols = false;
- // each symbol in the section is a separate map
- for i in symbols {
- let sym = self.symbol_table.get(i).ok_or(ParseError::SymbolNotFound {
- name: i.to_string(),
- })?;
- let start = sym.address as usize;
- let end = start + sym.size as usize;
- let data = §ion.data[start..end];
- let name = sym
- .name
- .as_ref()
- .ok_or(ParseError::MapSymbolNameNotFound { i: *i })?;
- let def = parse_map_def(name, data)?;
- maps.insert(
- name.to_string(),
- Map::Legacy(LegacyMap {
- section_index: section.index.0,
- section_kind: section.kind,
- symbol_index: Some(sym.index),
- def,
- data: Vec::new(),
- }),
- );
- have_symbols = true;
- }
- if !have_symbols {
- return Err(ParseError::NoSymbolsForSection {
- section_name: section.name.to_owned(),
- });
- }
- Ok(())
- }
- fn parse_section(&mut self, section: Section) -> Result<(), ParseError> {
- self.section_infos
- .insert(section.name.to_owned(), (section.index, section.size));
- match section.kind {
- BpfSectionKind::Data | BpfSectionKind::Rodata | BpfSectionKind::Bss => {
- self.maps
- .insert(section.name.to_string(), parse_data_map_section(§ion)?);
- }
- BpfSectionKind::Text => self.parse_text_section(section)?,
- BpfSectionKind::Btf => self.parse_btf(§ion)?,
- BpfSectionKind::BtfExt => self.parse_btf_ext(§ion)?,
- BpfSectionKind::BtfMaps => self.parse_btf_maps(§ion)?,
- BpfSectionKind::Maps => {
- // take out self.maps so we can borrow the iterator below
- // without cloning or collecting
- let mut maps = mem::take(&mut self.maps);
- // extract the symbols for the .maps section, we'll need them
- // during parsing
- let symbols = self
- .symbols_by_section
- .get(§ion.index)
- .ok_or(ParseError::NoSymbolsForSection {
- section_name: section.name.to_owned(),
- })?
- .iter();
- let res = self.parse_maps_section(&mut maps, §ion, symbols);
- // put the maps back
- self.maps = maps;
- res?
- }
- BpfSectionKind::Program => {
- self.parse_programs(§ion)?;
- if !section.relocations.is_empty() {
- self.relocations.insert(
- section.index,
- section
- .relocations
- .into_iter()
- .map(|rel| (rel.offset, rel))
- .collect(),
- );
- }
- }
- BpfSectionKind::Undefined | BpfSectionKind::License | BpfSectionKind::Version => {}
- }
- Ok(())
- }
- /// Sanitize BPF functions.
- pub fn sanitize_functions(&mut self, features: &Features) {
- for function in self.functions.values_mut() {
- function.sanitize(features);
- }
- }
- }
- fn insn_is_helper_call(ins: &bpf_insn) -> bool {
- let klass = (ins.code & 0x07) as u32;
- let op = (ins.code & 0xF0) as u32;
- let src = (ins.code & 0x08) as u32;
- klass == BPF_JMP && op == BPF_CALL && src == BPF_K && ins.src_reg() == 0 && ins.dst_reg() == 0
- }
- const BPF_FUNC_PROBE_READ: i32 = 4;
- const BPF_FUNC_PROBE_READ_STR: i32 = 45;
- const BPF_FUNC_PROBE_READ_USER: i32 = 112;
- const BPF_FUNC_PROBE_READ_KERNEL: i32 = 113;
- const BPF_FUNC_PROBE_READ_USER_STR: i32 = 114;
- const BPF_FUNC_PROBE_READ_KERNEL_STR: i32 = 115;
- impl Function {
- fn sanitize(&mut self, features: &Features) {
- for inst in &mut self.instructions {
- if !insn_is_helper_call(inst) {
- continue;
- }
- match inst.imm {
- BPF_FUNC_PROBE_READ_USER | BPF_FUNC_PROBE_READ_KERNEL
- if !features.bpf_probe_read_kernel =>
- {
- inst.imm = BPF_FUNC_PROBE_READ;
- }
- BPF_FUNC_PROBE_READ_USER_STR | BPF_FUNC_PROBE_READ_KERNEL_STR
- if !features.bpf_probe_read_kernel =>
- {
- inst.imm = BPF_FUNC_PROBE_READ_STR;
- }
- _ => {}
- }
- }
- }
- }
- /// Errors caught during parsing the object file
- #[derive(Debug, thiserror::Error)]
- #[allow(missing_docs)]
- pub enum ParseError {
- #[error("error parsing ELF data")]
- ElfError(object::read::Error),
- /// Error parsing BTF object
- #[error("BTF error")]
- BtfError(#[from] BtfError),
- #[error("invalid license `{data:?}`: missing NULL terminator")]
- MissingLicenseNullTerminator { data: Vec<u8> },
- #[error("invalid license `{data:?}`")]
- InvalidLicense { data: Vec<u8> },
- #[error("invalid kernel version `{data:?}`")]
- InvalidKernelVersion { data: Vec<u8> },
- #[error("error parsing section with index {index}")]
- SectionError {
- index: usize,
- error: object::read::Error,
- },
- #[error("unsupported relocation target")]
- UnsupportedRelocationTarget,
- #[error("invalid program section `{section}`")]
- InvalidProgramSection { section: String },
- #[error("invalid program code")]
- InvalidProgramCode,
- #[error("error parsing map `{name}`")]
- InvalidMapDefinition { name: String },
- #[error("two or more symbols in section `{section_index}` have the same address {address:#X}")]
- SymbolTableConflict { section_index: usize, address: u64 },
- #[error("unknown symbol in section `{section_index}` at address {address:#X}")]
- UnknownSymbol { section_index: usize, address: u64 },
- #[error("invalid symbol, index `{index}` name: {}", .name.as_ref().unwrap_or(&"[unknown]".into()))]
- InvalidSymbol { index: usize, name: Option<String> },
- #[error("symbol {name} has size `{sym_size}`, but provided data is of size `{data_size}`")]
- InvalidGlobalData {
- name: String,
- sym_size: u64,
- data_size: usize,
- },
- #[error("symbol with name {name} not found in the symbols table")]
- SymbolNotFound { name: String },
- #[error("map for section with index {index} not found")]
- MapNotFound { index: usize },
- #[error("the map number {i} in the `maps` section doesn't have a symbol name")]
- MapSymbolNameNotFound { i: usize },
- #[error("no symbols found in the {section_name} section")]
- NoSymbolsForSection { section_name: String },
- /// No BTF parsed for object
- #[error("no BTF parsed for object")]
- NoBTF,
- }
- /// The kind of an ELF section.
- #[derive(Debug, Copy, Clone, Eq, PartialEq)]
- pub enum BpfSectionKind {
- /// Undefined
- Undefined,
- /// `maps`
- Maps,
- /// `.maps`
- BtfMaps,
- /// A program section
- Program,
- /// `.data`
- Data,
- /// `.rodata`
- Rodata,
- /// `.bss`
- Bss,
- /// `.text`
- Text,
- /// `.BTF`
- Btf,
- /// `.BTF.ext`
- BtfExt,
- /// `license`
- License,
- /// `version`
- Version,
- }
- impl BpfSectionKind {
- fn from_name(name: &str) -> BpfSectionKind {
- if name.starts_with("license") {
- BpfSectionKind::License
- } else if name.starts_with("version") {
- BpfSectionKind::Version
- } else if name.starts_with("maps") {
- BpfSectionKind::Maps
- } else if name.starts_with(".maps") {
- BpfSectionKind::BtfMaps
- } else if name.starts_with(".text") {
- BpfSectionKind::Text
- } else if name.starts_with(".bss") {
- BpfSectionKind::Bss
- } else if name.starts_with(".data") {
- BpfSectionKind::Data
- } else if name.starts_with(".rodata") {
- BpfSectionKind::Rodata
- } else if name == ".BTF" {
- BpfSectionKind::Btf
- } else if name == ".BTF.ext" {
- BpfSectionKind::BtfExt
- } else {
- BpfSectionKind::Undefined
- }
- }
- }
- #[derive(Debug)]
- struct Section<'a> {
- index: SectionIndex,
- kind: BpfSectionKind,
- address: u64,
- name: &'a str,
- data: &'a [u8],
- size: u64,
- relocations: Vec<Relocation>,
- }
- impl<'data, 'file, 'a> TryFrom<&'a ObjSection<'data, 'file>> for Section<'a> {
- type Error = ParseError;
- fn try_from(section: &'a ObjSection) -> Result<Section<'a>, ParseError> {
- let index = section.index();
- let map_err = |error| ParseError::SectionError {
- index: index.0,
- error,
- };
- let name = section.name().map_err(map_err)?;
- let kind = match BpfSectionKind::from_name(name) {
- BpfSectionKind::Undefined => {
- if section.kind() == SectionKind::Text && section.size() > 0 {
- BpfSectionKind::Program
- } else {
- BpfSectionKind::Undefined
- }
- }
- k => k,
- };
- Ok(Section {
- index,
- kind,
- address: section.address(),
- name,
- data: section.data().map_err(map_err)?,
- size: section.size(),
- relocations: section
- .relocations()
- .map(|(offset, r)| {
- Ok(Relocation {
- symbol_index: match r.target() {
- RelocationTarget::Symbol(index) => index.0,
- _ => return Err(ParseError::UnsupportedRelocationTarget),
- },
- offset,
- size: r.size(),
- })
- })
- .collect::<Result<Vec<_>, _>>()?,
- })
- }
- }
- fn parse_license(data: &[u8]) -> Result<CString, ParseError> {
- if data.len() < 2 {
- return Err(ParseError::InvalidLicense {
- data: data.to_vec(),
- });
- }
- if data[data.len() - 1] != 0 {
- return Err(ParseError::MissingLicenseNullTerminator {
- data: data.to_vec(),
- });
- }
- Ok(CStr::from_bytes_with_nul(data)
- .map_err(|_| ParseError::InvalidLicense {
- data: data.to_vec(),
- })?
- .to_owned())
- }
- fn parse_version(data: &[u8], endianness: object::Endianness) -> Result<Option<u32>, ParseError> {
- let data = match data.len() {
- 4 => data.try_into().unwrap(),
- _ => {
- return Err(ParseError::InvalidKernelVersion {
- data: data.to_vec(),
- })
- }
- };
- let v = match endianness {
- object::Endianness::Big => u32::from_be_bytes(data),
- object::Endianness::Little => u32::from_le_bytes(data),
- };
- Ok(if v == KERNEL_VERSION_ANY {
- None
- } else {
- Some(v)
- })
- }
- // Gets an integer value from a BTF map defintion K/V pair.
- // type_id should be a PTR to an ARRAY.
- // the value is encoded in the array nr_elems field.
- fn get_map_field(btf: &Btf, type_id: u32) -> Result<u32, BtfError> {
- let pty = match &btf.type_by_id(type_id)? {
- BtfType::Ptr(pty) => pty,
- other => {
- return Err(BtfError::UnexpectedBtfType {
- type_id: other.btf_type().unwrap_or(0),
- })
- }
- };
- // Safety: union
- let arr = match &btf.type_by_id(pty.btf_type)? {
- BtfType::Array(Array { array, .. }) => array,
- other => {
- return Err(BtfError::UnexpectedBtfType {
- type_id: other.btf_type().unwrap_or(0),
- })
- }
- };
- Ok(arr.len)
- }
- // Parsed '.bss' '.data' and '.rodata' sections. These sections are arrays of
- // bytes and are relocated based on their section index.
- fn parse_data_map_section(section: &Section) -> Result<Map, ParseError> {
- let (def, data) = match section.kind {
- BpfSectionKind::Bss | BpfSectionKind::Data | BpfSectionKind::Rodata => {
- let def = bpf_map_def {
- map_type: BPF_MAP_TYPE_ARRAY as u32,
- key_size: mem::size_of::<u32>() as u32,
- // We need to use section.size here since
- // .bss will always have data.len() == 0
- value_size: section.size as u32,
- max_entries: 1,
- map_flags: if section.kind == BpfSectionKind::Rodata {
- BPF_F_RDONLY_PROG
- } else {
- 0
- },
- ..Default::default()
- };
- (def, section.data.to_vec())
- }
- _ => unreachable!(),
- };
- Ok(Map::Legacy(LegacyMap {
- section_index: section.index.0,
- section_kind: section.kind,
- // Data maps don't require symbols to be relocated
- symbol_index: None,
- def,
- data,
- }))
- }
- fn parse_map_def(name: &str, data: &[u8]) -> Result<bpf_map_def, ParseError> {
- if data.len() < MINIMUM_MAP_SIZE {
- return Err(ParseError::InvalidMapDefinition {
- name: name.to_owned(),
- });
- }
- if data.len() < mem::size_of::<bpf_map_def>() {
- let mut map_def = bpf_map_def::default();
- unsafe {
- let map_def_ptr =
- from_raw_parts_mut(&mut map_def as *mut bpf_map_def as *mut u8, data.len());
- map_def_ptr.copy_from_slice(data);
- }
- Ok(map_def)
- } else {
- Ok(unsafe { ptr::read_unaligned(data.as_ptr() as *const bpf_map_def) })
- }
- }
- fn parse_btf_map_def(btf: &Btf, info: &DataSecEntry) -> Result<(String, BtfMapDef), BtfError> {
- let ty = match btf.type_by_id(info.btf_type)? {
- BtfType::Var(var) => var,
- other => {
- return Err(BtfError::UnexpectedBtfType {
- type_id: other.btf_type().unwrap_or(0),
- })
- }
- };
- let map_name = btf.string_at(ty.name_offset)?;
- let mut map_def = BtfMapDef::default();
- // Safety: union
- let root_type = btf.resolve_type(ty.btf_type)?;
- let s = match btf.type_by_id(root_type)? {
- BtfType::Struct(s) => s,
- other => {
- return Err(BtfError::UnexpectedBtfType {
- type_id: other.btf_type().unwrap_or(0),
- })
- }
- };
- for m in &s.members {
- match btf.string_at(m.name_offset)?.as_ref() {
- "type" => {
- map_def.map_type = get_map_field(btf, m.btf_type)?;
- }
- "key" => {
- if let BtfType::Ptr(pty) = btf.type_by_id(m.btf_type)? {
- // Safety: union
- let t = pty.btf_type;
- map_def.key_size = btf.type_size(t)? as u32;
- map_def.btf_key_type_id = t;
- } else {
- return Err(BtfError::UnexpectedBtfType {
- type_id: m.btf_type,
- });
- }
- }
- "key_size" => {
- map_def.key_size = get_map_field(btf, m.btf_type)?;
- }
- "value" => {
- if let BtfType::Ptr(pty) = btf.type_by_id(m.btf_type)? {
- let t = pty.btf_type;
- map_def.value_size = btf.type_size(t)? as u32;
- map_def.btf_value_type_id = t;
- } else {
- return Err(BtfError::UnexpectedBtfType {
- type_id: m.btf_type,
- });
- }
- }
- "value_size" => {
- map_def.value_size = get_map_field(btf, m.btf_type)?;
- }
- "max_entries" => {
- map_def.max_entries = get_map_field(btf, m.btf_type)?;
- }
- "map_flags" => {
- map_def.map_flags = get_map_field(btf, m.btf_type)?;
- }
- "pinning" => {
- let pinning = get_map_field(btf, m.btf_type)?;
- map_def.pinning = PinningType::try_from(pinning).unwrap_or_else(|_| {
- debug!("{} is not a valid pin type. using PIN_NONE", pinning);
- PinningType::None
- });
- }
- other => {
- debug!("skipping unknown map section: {}", other);
- continue;
- }
- }
- }
- Ok((map_name.to_string(), map_def))
- }
- /// Parses a [bpf_map_info] into a [Map].
- pub fn parse_map_info(info: bpf_map_info, pinned: PinningType) -> Map {
- if info.btf_key_type_id != 0 {
- Map::Btf(BtfMap {
- def: BtfMapDef {
- map_type: info.type_,
- key_size: info.key_size,
- value_size: info.value_size,
- max_entries: info.max_entries,
- map_flags: info.map_flags,
- pinning: pinned,
- btf_key_type_id: info.btf_key_type_id,
- btf_value_type_id: info.btf_value_type_id,
- },
- section_index: 0,
- symbol_index: 0,
- data: Vec::new(),
- })
- } else {
- Map::Legacy(LegacyMap {
- def: bpf_map_def {
- map_type: info.type_,
- key_size: info.key_size,
- value_size: info.value_size,
- max_entries: info.max_entries,
- map_flags: info.map_flags,
- pinning: pinned,
- id: info.id,
- },
- section_index: 0,
- symbol_index: None,
- section_kind: BpfSectionKind::Undefined,
- data: Vec::new(),
- })
- }
- }
- /// Copies a block of eBPF instructions
- pub fn copy_instructions(data: &[u8]) -> Result<Vec<bpf_insn>, ParseError> {
- if data.len() % mem::size_of::<bpf_insn>() > 0 {
- return Err(ParseError::InvalidProgramCode);
- }
- let instructions = data
- .chunks_exact(mem::size_of::<bpf_insn>())
- .map(|d| unsafe { ptr::read_unaligned(d.as_ptr() as *const bpf_insn) })
- .collect::<Vec<_>>();
- Ok(instructions)
- }
- fn get_func_and_line_info(
- btf_ext: Option<&BtfExt>,
- symbol: &Symbol,
- section: &Section,
- offset: usize,
- rewrite_insn_off: bool,
- ) -> (FuncSecInfo, LineSecInfo, usize, usize) {
- btf_ext
- .map(|btf_ext| {
- let instruction_offset = (offset / INS_SIZE) as u32;
- let symbol_size_instructions = (symbol.size as usize / INS_SIZE) as u32;
- let mut func_info = btf_ext.func_info.get(section.name);
- func_info.func_info.retain_mut(|f| {
- let retain = f.insn_off == instruction_offset;
- if retain && rewrite_insn_off {
- f.insn_off = 0;
- }
- retain
- });
- let mut line_info = btf_ext.line_info.get(section.name);
- line_info
- .line_info
- .retain_mut(|l| match l.insn_off.checked_sub(instruction_offset) {
- None => false,
- Some(insn_off) => {
- let retain = insn_off < symbol_size_instructions;
- if retain && rewrite_insn_off {
- l.insn_off = insn_off
- }
- retain
- }
- });
- (
- func_info,
- line_info,
- btf_ext.func_info_rec_size(),
- btf_ext.line_info_rec_size(),
- )
- })
- .unwrap_or_default()
- }
- #[cfg(test)]
- mod tests {
- use alloc::vec;
- use assert_matches::assert_matches;
- use object::Endianness;
- use super::*;
- use crate::maps::PinningType;
- const FAKE_INS_LEN: u64 = 8;
- fn fake_section<'a>(
- kind: BpfSectionKind,
- name: &'a str,
- data: &'a [u8],
- index: Option<usize>,
- ) -> Section<'a> {
- let idx = index.unwrap_or(0);
- Section {
- index: SectionIndex(idx),
- kind,
- address: 0,
- name,
- data,
- size: data.len() as u64,
- relocations: Vec::new(),
- }
- }
- fn fake_ins() -> bpf_insn {
- bpf_insn {
- code: 0,
- _bitfield_align_1: [],
- _bitfield_1: bpf_insn::new_bitfield_1(0, 0),
- off: 0,
- imm: 0,
- }
- }
- fn fake_sym(obj: &mut Object, section_index: usize, address: u64, name: &str, size: u64) {
- let idx = obj.symbol_table.len();
- obj.symbol_table.insert(
- idx + 1,
- Symbol {
- index: idx + 1,
- section_index: Some(section_index),
- name: Some(name.to_string()),
- address,
- size,
- is_definition: false,
- kind: SymbolKind::Text,
- },
- );
- obj.symbols_by_section
- .entry(SectionIndex(section_index))
- .or_default()
- .push(idx + 1);
- }
- fn bytes_of<T>(val: &T) -> &[u8] {
- // Safety: This is for testing only
- unsafe { crate::util::bytes_of(val) }
- }
- #[test]
- fn test_parse_generic_error() {
- assert_matches!(Object::parse(&b"foo"[..]), Err(ParseError::ElfError(_)))
- }
- #[test]
- fn test_parse_license() {
- assert_matches!(parse_license(b""), Err(ParseError::InvalidLicense { .. }));
- assert_matches!(parse_license(b"\0"), Err(ParseError::InvalidLicense { .. }));
- assert_matches!(
- parse_license(b"GPL"),
- Err(ParseError::MissingLicenseNullTerminator { .. })
- );
- assert_eq!(parse_license(b"GPL\0").unwrap().to_str().unwrap(), "GPL");
- }
- #[test]
- fn test_parse_version() {
- assert_matches!(
- parse_version(b"", Endianness::Little),
- Err(ParseError::InvalidKernelVersion { .. })
- );
- assert_matches!(
- parse_version(b"123", Endianness::Little),
- Err(ParseError::InvalidKernelVersion { .. })
- );
- assert_matches!(
- parse_version(&0xFFFF_FFFEu32.to_le_bytes(), Endianness::Little),
- Ok(None)
- );
- assert_matches!(
- parse_version(&0xFFFF_FFFEu32.to_be_bytes(), Endianness::Big),
- Ok(None)
- );
- assert_matches!(
- parse_version(&1234u32.to_le_bytes(), Endianness::Little),
- Ok(Some(1234))
- );
- }
- #[test]
- fn test_parse_map_def_error() {
- assert_matches!(
- parse_map_def("foo", &[]),
- Err(ParseError::InvalidMapDefinition { .. })
- );
- }
- #[test]
- fn test_parse_map_short() {
- let def = bpf_map_def {
- map_type: 1,
- key_size: 2,
- value_size: 3,
- max_entries: 4,
- map_flags: 5,
- id: 0,
- pinning: PinningType::None,
- };
- assert_eq!(
- parse_map_def("foo", &bytes_of(&def)[..MINIMUM_MAP_SIZE]).unwrap(),
- def
- );
- }
- #[test]
- fn test_parse_map_def() {
- let def = bpf_map_def {
- map_type: 1,
- key_size: 2,
- value_size: 3,
- max_entries: 4,
- map_flags: 5,
- id: 6,
- pinning: PinningType::ByName,
- };
- assert_eq!(parse_map_def("foo", bytes_of(&def)).unwrap(), def);
- }
- #[test]
- fn test_parse_map_def_with_padding() {
- let def = bpf_map_def {
- map_type: 1,
- key_size: 2,
- value_size: 3,
- max_entries: 4,
- map_flags: 5,
- id: 6,
- pinning: PinningType::ByName,
- };
- let mut buf = [0u8; 128];
- unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, def) };
- assert_eq!(parse_map_def("foo", &buf).unwrap(), def);
- }
- #[test]
- fn test_parse_map_data() {
- let map_data = b"map data";
- assert_matches!(
- parse_data_map_section(
- &fake_section(
- BpfSectionKind::Data,
- ".bss",
- map_data,
- None,
- ),
- ),
- Ok(Map::Legacy(LegacyMap {
- section_index: 0,
- section_kind: BpfSectionKind::Data,
- symbol_index: None,
- def: bpf_map_def {
- map_type: _map_type,
- key_size: 4,
- value_size,
- max_entries: 1,
- map_flags: 0,
- id: 0,
- pinning: PinningType::None,
- },
- data,
- })) if data == map_data && value_size == map_data.len() as u32
- )
- }
- fn fake_obj() -> Object {
- Object::new(Endianness::Little, CString::new("GPL").unwrap(), None)
- }
- #[test]
- fn sanitizes_empty_btf_files_to_none() {
- let mut obj = fake_obj();
- obj.parse_section(fake_section(
- BpfSectionKind::Btf,
- ".BTF",
- &[
- 159, 235, 1, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
- ],
- None,
- ))
- .unwrap();
- obj.parse_section(fake_section(
- BpfSectionKind::BtfExt,
- ".BTF.ext",
- &[
- 159, 235, 1, 0, 24, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0,
- 0, 0, 16, 0, 0, 0,
- ],
- None,
- ))
- .unwrap();
- let btf = obj.fixup_and_sanitize_btf(&BtfFeatures::default()).unwrap();
- assert!(btf.is_none());
- }
- #[test]
- fn test_parse_program_error() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", 1);
- assert_matches!(
- obj.parse_programs(&fake_section(
- BpfSectionKind::Program,
- "kprobe/foo",
- &42u32.to_ne_bytes(),
- None,
- ),),
- Err(ParseError::InvalidProgramCode)
- );
- }
- #[test]
- fn test_parse_program() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- obj.parse_programs(&fake_section(
- BpfSectionKind::Program,
- "kprobe/foo",
- bytes_of(&fake_ins()),
- None,
- ))
- .unwrap();
- let prog_foo = obj.programs.get("foo").unwrap();
- assert_matches!(prog_foo, Program {
- license,
- kernel_version: None,
- section: ProgramSection::KProbe { .. },
- ..
- } => assert_eq!(license.to_str().unwrap(), "GPL"));
- assert_matches!(
- obj.functions.get(&prog_foo.function_key()),
- Some(Function {
- name,
- address: 0,
- section_index: SectionIndex(0),
- section_offset: 0,
- instructions,
- ..}) if name == "foo" && instructions.len() == 1
- )
- }
- #[test]
- fn test_parse_section_map() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", mem::size_of::<bpf_map_def>() as u64);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Maps,
- "maps/foo",
- bytes_of(&bpf_map_def {
- map_type: 1,
- key_size: 2,
- value_size: 3,
- max_entries: 4,
- map_flags: 5,
- ..Default::default()
- }),
- None,
- )),
- Ok(())
- );
- assert!(obj.maps.get("foo").is_some());
- }
- #[test]
- fn test_parse_multiple_program_in_same_section() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- fake_sym(&mut obj, 0, FAKE_INS_LEN, "bar", FAKE_INS_LEN);
- let insns = [fake_ins(), fake_ins()];
- let data = bytes_of(&insns);
- obj.parse_programs(&fake_section(BpfSectionKind::Program, "kprobe", data, None))
- .unwrap();
- let prog_foo = obj.programs.get("foo").unwrap();
- let function_foo = obj.functions.get(&prog_foo.function_key()).unwrap();
- let prog_bar = obj.programs.get("bar").unwrap();
- let function_bar = obj.functions.get(&prog_bar.function_key()).unwrap();
- assert_matches!(prog_foo, Program {
- license,
- kernel_version: None,
- section: ProgramSection::KProbe { .. },
- ..
- } => assert_eq!(license.to_str().unwrap(), "GPL"));
- assert_matches!(
- function_foo,
- Function {
- name,
- address: 0,
- section_index: SectionIndex(0),
- section_offset: 0,
- instructions,
- ..
- } if name == "foo" && instructions.len() == 1
- );
- assert_matches!(prog_bar, Program {
- license,
- kernel_version: None,
- section: ProgramSection::KProbe { .. },
- ..
- } => assert_eq!(license.to_str().unwrap(), "GPL"));
- assert_matches!(
- function_bar,
- Function {
- name,
- address: 8,
- section_index: SectionIndex(0),
- section_offset: 8,
- instructions,
- ..
- } if name == "bar" && instructions.len() == 1
- );
- }
- #[test]
- fn test_parse_section_multiple_maps() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", mem::size_of::<bpf_map_def>() as u64);
- fake_sym(&mut obj, 0, 28, "bar", mem::size_of::<bpf_map_def>() as u64);
- fake_sym(&mut obj, 0, 60, "baz", mem::size_of::<bpf_map_def>() as u64);
- let def = &bpf_map_def {
- map_type: 1,
- key_size: 2,
- value_size: 3,
- max_entries: 4,
- map_flags: 5,
- ..Default::default()
- };
- let map_data = bytes_of(def).to_vec();
- let mut buf = vec![];
- buf.extend(&map_data);
- buf.extend(&map_data);
- // throw in some padding
- buf.extend([0, 0, 0, 0]);
- buf.extend(&map_data);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Maps,
- "maps",
- buf.as_slice(),
- None
- )),
- Ok(())
- );
- assert!(obj.maps.get("foo").is_some());
- assert!(obj.maps.get("bar").is_some());
- assert!(obj.maps.get("baz").is_some());
- for map in obj.maps.values() {
- assert_matches!(map, Map::Legacy(m) => {
- assert_eq!(&m.def, def);
- })
- }
- }
- #[test]
- fn test_parse_section_data() {
- let mut obj = fake_obj();
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Data,
- ".bss",
- b"map data",
- None
- )),
- Ok(())
- );
- assert!(obj.maps.get(".bss").is_some());
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Data,
- ".rodata",
- b"map data",
- None
- )),
- Ok(())
- );
- assert!(obj.maps.get(".rodata").is_some());
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Data,
- ".rodata.boo",
- b"map data",
- None
- )),
- Ok(())
- );
- assert!(obj.maps.get(".rodata.boo").is_some());
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Data,
- ".data",
- b"map data",
- None
- )),
- Ok(())
- );
- assert!(obj.maps.get(".data").is_some());
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Data,
- ".data.boo",
- b"map data",
- None
- )),
- Ok(())
- );
- assert!(obj.maps.get(".data.boo").is_some());
- }
- #[test]
- fn test_parse_section_kprobe() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "kprobe/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::KProbe { .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_uprobe() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "uprobe/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::UProbe { .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_uprobe_sleepable() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "uprobe.s/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::UProbe {
- sleepable: true,
- ..
- },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_uretprobe() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "uretprobe/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::URetProbe { .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_uretprobe_sleepable() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "uretprobe.s/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::URetProbe {
- sleepable: true,
- ..
- },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_trace_point() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- fake_sym(&mut obj, 1, 0, "bar", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "tracepoint/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::TracePoint { .. },
- ..
- })
- );
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "tp/foo/bar",
- bytes_of(&fake_ins()),
- Some(1),
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("bar"),
- Some(Program {
- section: ProgramSection::TracePoint { .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_socket_filter() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "socket/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::SocketFilter { .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_xdp() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "xdp",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::Xdp { frags: false, .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_xdp_frags() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "xdp.frags",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::Xdp { frags: true, .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_raw_tp() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- fake_sym(&mut obj, 1, 0, "bar", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "raw_tp/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::RawTracePoint { .. },
- ..
- })
- );
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "raw_tracepoint/bar",
- bytes_of(&fake_ins()),
- Some(1)
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("bar"),
- Some(Program {
- section: ProgramSection::RawTracePoint { .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_lsm() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "lsm/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::Lsm {
- sleepable: false,
- ..
- },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_lsm_sleepable() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "lsm.s/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::Lsm {
- sleepable: true,
- ..
- },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_btf_tracepoint() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "tp_btf/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::BtfTracePoint { .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_skskb_unnamed() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "stream_parser", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "sk_skb/stream_parser",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("stream_parser"),
- Some(Program {
- section: ProgramSection::SkSkbStreamParser { .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_skskb_named() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "my_parser", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "sk_skb/stream_parser/my_parser",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("my_parser"),
- Some(Program {
- section: ProgramSection::SkSkbStreamParser { .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_fentry() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "fentry/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::FEntry { .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_fentry_sleepable() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "fentry.s/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::FEntry {
- sleepable: true,
- ..
- },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_fexit() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "fexit/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::FExit { .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_fexit_sleepable() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "fexit.s/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::FExit {
- sleepable: true,
- ..
- },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_cgroup_skb_ingress_unnamed() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "ingress", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "cgroup_skb/ingress",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("ingress"),
- Some(Program {
- section: ProgramSection::CgroupSkbIngress { .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_cgroup_skb_ingress_named() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "cgroup_skb/ingress/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::CgroupSkbIngress { .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_cgroup_skb_no_direction_unamed() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "skb", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "cgroup/skb",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("skb"),
- Some(Program {
- section: ProgramSection::CgroupSkb { .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_cgroup_skb_no_direction_named() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "cgroup/skb/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::CgroupSkb { .. },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_sock_addr_named() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "cgroup/connect4/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::CgroupSockAddr {
- attach_type: CgroupSockAddrAttachType::Connect4,
- ..
- },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_sock_addr_unnamed() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "connect4", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "cgroup/connect4",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("connect4"),
- Some(Program {
- section: ProgramSection::CgroupSockAddr {
- attach_type: CgroupSockAddrAttachType::Connect4,
- ..
- },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_sockopt_named() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "cgroup/getsockopt/foo",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("foo"),
- Some(Program {
- section: ProgramSection::CgroupSockopt {
- attach_type: CgroupSockoptAttachType::Get,
- ..
- },
- ..
- })
- );
- }
- #[test]
- fn test_parse_section_sockopt_unnamed() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "getsockopt", FAKE_INS_LEN);
- assert_matches!(
- obj.parse_section(fake_section(
- BpfSectionKind::Program,
- "cgroup/getsockopt",
- bytes_of(&fake_ins()),
- None
- )),
- Ok(())
- );
- assert_matches!(
- obj.programs.get("getsockopt"),
- Some(Program {
- section: ProgramSection::CgroupSockopt {
- attach_type: CgroupSockoptAttachType::Get,
- ..
- },
- ..
- })
- );
- }
- #[test]
- fn test_patch_map_data() {
- let mut obj = fake_obj();
- obj.maps.insert(
- ".rodata".to_owned(),
- Map::Legacy(LegacyMap {
- def: bpf_map_def {
- map_type: BPF_MAP_TYPE_ARRAY as u32,
- key_size: mem::size_of::<u32>() as u32,
- value_size: 3,
- max_entries: 1,
- map_flags: BPF_F_RDONLY_PROG,
- id: 1,
- pinning: PinningType::None,
- },
- section_index: 1,
- section_kind: BpfSectionKind::Rodata,
- symbol_index: Some(1),
- data: vec![0, 0, 0],
- }),
- );
- obj.symbol_table.insert(
- 1,
- Symbol {
- index: 1,
- section_index: Some(1),
- name: Some("my_config".to_owned()),
- address: 0,
- size: 3,
- is_definition: true,
- kind: SymbolKind::Data,
- },
- );
- let test_data: &[u8] = &[1, 2, 3];
- obj.patch_map_data(HashMap::from([
- ("my_config", (test_data, true)),
- ("optional_variable", (test_data, false)),
- ]))
- .unwrap();
- let map = obj.maps.get(".rodata").unwrap();
- assert_eq!(test_data, map.data());
- }
- #[test]
- fn test_parse_btf_map_section() {
- let mut obj = fake_obj();
- fake_sym(&mut obj, 0, 0, "map_1", 0);
- fake_sym(&mut obj, 0, 0, "map_2", 0);
- // generated from:
- // objcopy --dump-section .BTF=test.btf ./target/bpfel-unknown-none/debug/multimap-btf.bpf.o
- // hexdump -v -e '7/1 "0x%02X, " 1/1 " 0x%02X,\n"' test.btf
- let data: &[u8] = &[
- 0x9F, 0xEB, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x01,
- 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0xCC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x02, 0x06, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
- 0x07, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00,
- 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
- 0x09, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0A, 0x00,
- 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00,
- 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0C, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x05, 0x00,
- 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
- 0x80, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xC0, 0x00,
- 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x0D, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x20, 0x00,
- 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x4A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x4E, 0x00,
- 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
- 0x0B, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x0D, 0x02, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
- 0x70, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0C, 0x12, 0x00, 0x00, 0x00, 0xB0, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00,
- 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xB5, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x0E, 0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xBE, 0x01,
- 0x00, 0x00, 0x02, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xC4, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0F,
- 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x00, 0x69, 0x6E, 0x74, 0x00, 0x5F, 0x5F, 0x41, 0x52, 0x52, 0x41, 0x59,
- 0x5F, 0x53, 0x49, 0x5A, 0x45, 0x5F, 0x54, 0x59, 0x50, 0x45, 0x5F, 0x5F, 0x00, 0x5F,
- 0x5F, 0x75, 0x33, 0x32, 0x00, 0x75, 0x6E, 0x73, 0x69, 0x67, 0x6E, 0x65, 0x64, 0x20,
- 0x69, 0x6E, 0x74, 0x00, 0x5F, 0x5F, 0x75, 0x36, 0x34, 0x00, 0x75, 0x6E, 0x73, 0x69,
- 0x67, 0x6E, 0x65, 0x64, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x6C, 0x6F, 0x6E, 0x67,
- 0x00, 0x74, 0x79, 0x70, 0x65, 0x00, 0x6B, 0x65, 0x79, 0x00, 0x76, 0x61, 0x6C, 0x75,
- 0x65, 0x00, 0x6D, 0x61, 0x78, 0x5F, 0x65, 0x6E, 0x74, 0x72, 0x69, 0x65, 0x73, 0x00,
- 0x6D, 0x61, 0x70, 0x5F, 0x31, 0x00, 0x6D, 0x61, 0x70, 0x5F, 0x32, 0x00, 0x63, 0x74,
- 0x78, 0x00, 0x62, 0x70, 0x66, 0x5F, 0x70, 0x72, 0x6F, 0x67, 0x00, 0x74, 0x72, 0x61,
- 0x63, 0x65, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x00, 0x2F, 0x76, 0x61, 0x72, 0x2F, 0x68,
- 0x6F, 0x6D, 0x65, 0x2F, 0x64, 0x61, 0x76, 0x65, 0x2F, 0x64, 0x65, 0x76, 0x2F, 0x61,
- 0x79, 0x61, 0x2D, 0x72, 0x73, 0x2F, 0x61, 0x79, 0x61, 0x2F, 0x74, 0x65, 0x73, 0x74,
- 0x2F, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2D, 0x65,
- 0x62, 0x70, 0x66, 0x2F, 0x73, 0x72, 0x63, 0x2F, 0x62, 0x70, 0x66, 0x2F, 0x6D, 0x75,
- 0x6C, 0x74, 0x69, 0x6D, 0x61, 0x70, 0x2D, 0x62, 0x74, 0x66, 0x2E, 0x62, 0x70, 0x66,
- 0x2E, 0x63, 0x00, 0x69, 0x6E, 0x74, 0x20, 0x62, 0x70, 0x66, 0x5F, 0x70, 0x72, 0x6F,
- 0x67, 0x28, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x2A, 0x63, 0x74, 0x78, 0x29, 0x00, 0x09,
- 0x5F, 0x5F, 0x75, 0x33, 0x32, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x3D, 0x20, 0x30, 0x3B,
- 0x00, 0x09, 0x5F, 0x5F, 0x75, 0x36, 0x34, 0x20, 0x74, 0x77, 0x65, 0x6E, 0x74, 0x79,
- 0x5F, 0x66, 0x6F, 0x75, 0x72, 0x20, 0x3D, 0x20, 0x32, 0x34, 0x3B, 0x00, 0x09, 0x5F,
- 0x5F, 0x75, 0x36, 0x34, 0x20, 0x66, 0x6F, 0x72, 0x74, 0x79, 0x5F, 0x74, 0x77, 0x6F,
- 0x20, 0x3D, 0x20, 0x34, 0x32, 0x3B, 0x00, 0x20, 0x20, 0x20, 0x20, 0x62, 0x70, 0x66,
- 0x5F, 0x6D, 0x61, 0x70, 0x5F, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5F, 0x65, 0x6C,
- 0x65, 0x6D, 0x28, 0x26, 0x6D, 0x61, 0x70, 0x5F, 0x31, 0x2C, 0x20, 0x26, 0x6B, 0x65,
- 0x79, 0x2C, 0x20, 0x26, 0x74, 0x77, 0x65, 0x6E, 0x74, 0x79, 0x5F, 0x66, 0x6F, 0x75,
- 0x72, 0x2C, 0x20, 0x42, 0x50, 0x46, 0x5F, 0x41, 0x4E, 0x59, 0x29, 0x3B, 0x00, 0x20,
- 0x20, 0x20, 0x20, 0x62, 0x70, 0x66, 0x5F, 0x6D, 0x61, 0x70, 0x5F, 0x75, 0x70, 0x64,
- 0x61, 0x74, 0x65, 0x5F, 0x65, 0x6C, 0x65, 0x6D, 0x28, 0x26, 0x6D, 0x61, 0x70, 0x5F,
- 0x32, 0x2C, 0x20, 0x26, 0x6B, 0x65, 0x79, 0x2C, 0x20, 0x26, 0x66, 0x6F, 0x72, 0x74,
- 0x79, 0x5F, 0x74, 0x77, 0x6F, 0x2C, 0x20, 0x42, 0x50, 0x46, 0x5F, 0x41, 0x4E, 0x59,
- 0x29, 0x3B, 0x00, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x30, 0x3B, 0x00,
- 0x63, 0x68, 0x61, 0x72, 0x00, 0x5F, 0x6C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, 0x00,
- 0x2E, 0x6D, 0x61, 0x70, 0x73, 0x00, 0x6C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, 0x00,
- ];
- let btf_section = fake_section(BpfSectionKind::Btf, ".BTF", data, None);
- obj.parse_section(btf_section).unwrap();
- let map_section = fake_section(BpfSectionKind::BtfMaps, ".maps", &[], None);
- obj.parse_section(map_section).unwrap();
- let map = obj.maps.get("map_1").unwrap();
- assert_matches!(map, Map::Btf(m) => {
- assert_eq!(m.def.key_size, 4);
- assert_eq!(m.def.value_size, 8);
- assert_eq!(m.def.max_entries, 1);
- });
- }
- }
|