12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684 |
- //! 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, str::FromStr};
- use log::debug;
- use object::{
- read::{Object as ElfObject, ObjectSection, Section as ObjSection},
- Endianness, ObjectSymbol, ObjectSymbolTable, RelocationTarget, SectionIndex, SectionKind,
- SymbolKind,
- };
- use crate::{
- btf::BtfFeatures,
- generated::{BPF_CALL, BPF_JMP, BPF_K},
- maps::{BtfMap, LegacyMap, Map, MINIMUM_MAP_SIZE},
- programs::XdpAttachType,
- relocation::*,
- util::HashMap,
- };
- #[cfg(not(feature = "std"))]
- use crate::std;
- use crate::{
- btf::{Btf, BtfError, BtfExt, BtfType},
- generated::{bpf_insn, bpf_map_info, bpf_map_type::BPF_MAP_TYPE_ARRAY, BPF_F_RDONLY_PROG},
- maps::{bpf_map_def, BtfMapDef, PinningType},
- programs::{CgroupSockAddrAttachType, CgroupSockAttachType, CgroupSockoptAttachType},
- };
- use core::slice::from_raw_parts_mut;
- use crate::btf::{Array, DataSecEntry, FuncSecInfo, LineSecInfo};
- 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,
- devmap_hash_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,
- devmap_hash_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,
- devmap_hash_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
- }
- /// Returns whether XDP Hash Device Maps support chained program IDs.
- pub fn devmap_hash_prog_id(&self) -> bool {
- self.devmap_hash_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);
- });
- }
- }
|