relocation.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. //! Program relocation handling.
  2. use core::mem;
  3. use alloc::{borrow::ToOwned, collections::BTreeMap, string::String};
  4. use log::debug;
  5. use object::{SectionIndex, SymbolKind};
  6. use crate::{
  7. generated::{
  8. bpf_insn, BPF_CALL, BPF_JMP, BPF_K, BPF_PSEUDO_CALL, BPF_PSEUDO_FUNC, BPF_PSEUDO_MAP_FD,
  9. BPF_PSEUDO_MAP_VALUE,
  10. },
  11. maps::Map,
  12. obj::{Function, Object},
  13. util::{HashMap, HashSet},
  14. BpfSectionKind,
  15. };
  16. #[cfg(not(feature = "std"))]
  17. use crate::std;
  18. pub(crate) const INS_SIZE: usize = mem::size_of::<bpf_insn>();
  19. /// The error type returned by [`Object::relocate_maps`] and [`Object::relocate_calls`]
  20. #[derive(thiserror::Error, Debug)]
  21. #[error("error relocating `{function}`")]
  22. pub struct BpfRelocationError {
  23. /// The function name
  24. function: String,
  25. #[source]
  26. /// The original error
  27. error: RelocationError,
  28. }
  29. /// Relocation failures
  30. #[derive(Debug, thiserror::Error)]
  31. pub enum RelocationError {
  32. /// Unknown symbol
  33. #[error("unknown symbol, index `{index}`")]
  34. UnknownSymbol {
  35. /// The symbol index
  36. index: usize,
  37. },
  38. /// Section not found
  39. #[error("section `{section_index}` not found, referenced by symbol `{}` #{symbol_index}",
  40. .symbol_name.clone().unwrap_or_default())]
  41. SectionNotFound {
  42. /// The section index
  43. section_index: usize,
  44. /// The symbol index
  45. symbol_index: usize,
  46. /// The symbol name
  47. symbol_name: Option<String>,
  48. },
  49. /// Unknown function
  50. #[error("function {address:#x} not found while relocating `{caller_name}`")]
  51. UnknownFunction {
  52. /// The function address
  53. address: u64,
  54. /// The caller name
  55. caller_name: String,
  56. },
  57. /// Unknown function
  58. #[error("program at section {section_index} and address {address:#x} was not found while relocating")]
  59. UnknownProgram {
  60. /// The function section index
  61. section_index: usize,
  62. /// The function address
  63. address: u64,
  64. },
  65. /// Referenced map not created yet
  66. #[error("the map `{name}` at section `{section_index}` has not been created")]
  67. MapNotCreated {
  68. /// The section index
  69. section_index: usize,
  70. /// The map name
  71. name: String,
  72. },
  73. /// Invalid relocation offset
  74. #[error("invalid offset `{offset}` applying relocation #{relocation_number}")]
  75. InvalidRelocationOffset {
  76. /// The relocation offset
  77. offset: u64,
  78. /// The relocation number
  79. relocation_number: usize,
  80. },
  81. }
  82. #[derive(Debug, Copy, Clone)]
  83. pub(crate) struct Relocation {
  84. // byte offset of the instruction to be relocated
  85. pub(crate) offset: u64,
  86. pub(crate) size: u8,
  87. // index of the symbol to relocate to
  88. pub(crate) symbol_index: usize,
  89. }
  90. #[derive(Debug, Clone)]
  91. pub(crate) struct Symbol {
  92. pub(crate) index: usize,
  93. pub(crate) section_index: Option<usize>,
  94. pub(crate) name: Option<String>,
  95. pub(crate) address: u64,
  96. pub(crate) size: u64,
  97. pub(crate) is_definition: bool,
  98. pub(crate) kind: SymbolKind,
  99. }
  100. impl Object {
  101. /// Relocates the map references
  102. pub fn relocate_maps<'a, I: Iterator<Item = (&'a str, Option<i32>, &'a Map)>>(
  103. &mut self,
  104. maps: I,
  105. text_sections: &HashSet<usize>,
  106. ) -> Result<(), BpfRelocationError> {
  107. let mut maps_by_section = HashMap::new();
  108. let mut maps_by_symbol = HashMap::new();
  109. for (name, fd, map) in maps {
  110. maps_by_section.insert(map.section_index(), (name, fd, map));
  111. if let Some(index) = map.symbol_index() {
  112. maps_by_symbol.insert(index, (name, fd, map));
  113. }
  114. }
  115. for function in self.functions.values_mut() {
  116. if let Some(relocations) = self.relocations.get(&function.section_index) {
  117. relocate_maps(
  118. function,
  119. relocations.values(),
  120. &maps_by_section,
  121. &maps_by_symbol,
  122. &self.symbol_table,
  123. text_sections,
  124. )
  125. .map_err(|error| BpfRelocationError {
  126. function: function.name.clone(),
  127. error,
  128. })?;
  129. }
  130. }
  131. Ok(())
  132. }
  133. /// Relocates function calls
  134. pub fn relocate_calls(
  135. &mut self,
  136. text_sections: &HashSet<usize>,
  137. ) -> Result<(), BpfRelocationError> {
  138. for (name, program) in self.programs.iter() {
  139. let linker = FunctionLinker::new(
  140. &self.functions,
  141. &self.relocations,
  142. &self.symbol_table,
  143. text_sections,
  144. );
  145. let func_orig =
  146. self.functions
  147. .get(&program.function_key())
  148. .ok_or_else(|| BpfRelocationError {
  149. function: name.clone(),
  150. error: RelocationError::UnknownProgram {
  151. section_index: program.section_index,
  152. address: program.address,
  153. },
  154. })?;
  155. let func = linker.link(func_orig).map_err(|error| BpfRelocationError {
  156. function: name.to_owned(),
  157. error,
  158. })?;
  159. self.functions.insert(program.function_key(), func);
  160. }
  161. Ok(())
  162. }
  163. }
  164. fn relocate_maps<'a, I: Iterator<Item = &'a Relocation>>(
  165. fun: &mut Function,
  166. relocations: I,
  167. maps_by_section: &HashMap<usize, (&str, Option<i32>, &Map)>,
  168. maps_by_symbol: &HashMap<usize, (&str, Option<i32>, &Map)>,
  169. symbol_table: &HashMap<usize, Symbol>,
  170. text_sections: &HashSet<usize>,
  171. ) -> Result<(), RelocationError> {
  172. let section_offset = fun.section_offset;
  173. let instructions = &mut fun.instructions;
  174. let function_size = instructions.len() * INS_SIZE;
  175. for (rel_n, rel) in relocations.enumerate() {
  176. let rel_offset = rel.offset as usize;
  177. if rel_offset < section_offset || rel_offset >= section_offset + function_size {
  178. // the relocation doesn't apply to this function
  179. continue;
  180. }
  181. // make sure that the relocation offset is properly aligned
  182. let ins_offset = rel_offset - section_offset;
  183. if ins_offset % INS_SIZE != 0 {
  184. return Err(RelocationError::InvalidRelocationOffset {
  185. offset: rel.offset,
  186. relocation_number: rel_n,
  187. });
  188. }
  189. let ins_index = ins_offset / INS_SIZE;
  190. // a map relocation points to the ELF section that contains the map
  191. let sym = symbol_table
  192. .get(&rel.symbol_index)
  193. .ok_or(RelocationError::UnknownSymbol {
  194. index: rel.symbol_index,
  195. })?;
  196. let Some(section_index) = sym.section_index else {
  197. // this is not a map relocation
  198. continue;
  199. };
  200. // calls and relocation to .text symbols are handled in a separate step
  201. if insn_is_call(&instructions[ins_index]) || text_sections.contains(&section_index) {
  202. continue;
  203. }
  204. let (name, fd, map) = if let Some(m) = maps_by_symbol.get(&rel.symbol_index) {
  205. let map = &m.2;
  206. debug!(
  207. "relocating map by symbol index {:?}, kind {:?} at insn {ins_index} in section {}",
  208. map.symbol_index(),
  209. map.section_kind(),
  210. fun.section_index.0
  211. );
  212. debug_assert_eq!(map.symbol_index().unwrap(), rel.symbol_index);
  213. m
  214. } else {
  215. let Some(m) = maps_by_section.get(&section_index) else {
  216. debug!("failed relocating map by section index {}", section_index);
  217. return Err(RelocationError::SectionNotFound {
  218. symbol_index: rel.symbol_index,
  219. symbol_name: sym.name.clone(),
  220. section_index,
  221. });
  222. };
  223. let map = &m.2;
  224. debug!(
  225. "relocating map by section index {}, kind {:?} at insn {ins_index} in section {}",
  226. map.section_index(),
  227. map.section_kind(),
  228. fun.section_index.0,
  229. );
  230. debug_assert_eq!(map.symbol_index(), None);
  231. debug_assert!(matches!(
  232. map.section_kind(),
  233. BpfSectionKind::Bss | BpfSectionKind::Data | BpfSectionKind::Rodata
  234. ),);
  235. m
  236. };
  237. debug_assert_eq!(map.section_index(), section_index);
  238. let map_fd = fd.ok_or_else(|| RelocationError::MapNotCreated {
  239. name: (*name).into(),
  240. section_index,
  241. })?;
  242. if !map.data().is_empty() {
  243. instructions[ins_index].set_src_reg(BPF_PSEUDO_MAP_VALUE as u8);
  244. instructions[ins_index + 1].imm = instructions[ins_index].imm + sym.address as i32;
  245. } else {
  246. instructions[ins_index].set_src_reg(BPF_PSEUDO_MAP_FD as u8);
  247. }
  248. instructions[ins_index].imm = map_fd;
  249. }
  250. Ok(())
  251. }
  252. struct FunctionLinker<'a> {
  253. functions: &'a BTreeMap<(usize, u64), Function>,
  254. linked_functions: HashMap<u64, usize>,
  255. relocations: &'a HashMap<SectionIndex, HashMap<u64, Relocation>>,
  256. symbol_table: &'a HashMap<usize, Symbol>,
  257. text_sections: &'a HashSet<usize>,
  258. }
  259. impl<'a> FunctionLinker<'a> {
  260. fn new(
  261. functions: &'a BTreeMap<(usize, u64), Function>,
  262. relocations: &'a HashMap<SectionIndex, HashMap<u64, Relocation>>,
  263. symbol_table: &'a HashMap<usize, Symbol>,
  264. text_sections: &'a HashSet<usize>,
  265. ) -> FunctionLinker<'a> {
  266. FunctionLinker {
  267. functions,
  268. linked_functions: HashMap::new(),
  269. relocations,
  270. symbol_table,
  271. text_sections,
  272. }
  273. }
  274. fn link(mut self, program_function: &Function) -> Result<Function, RelocationError> {
  275. let mut fun = program_function.clone();
  276. // relocate calls in the program's main function. As relocation happens,
  277. // it will trigger linking in all the callees.
  278. self.relocate(&mut fun, program_function)?;
  279. // this now includes the program function plus all the other functions called during
  280. // execution
  281. Ok(fun)
  282. }
  283. fn link_function(
  284. &mut self,
  285. program: &mut Function,
  286. fun: &Function,
  287. ) -> Result<usize, RelocationError> {
  288. if let Some(fun_ins_index) = self.linked_functions.get(&fun.address) {
  289. return Ok(*fun_ins_index);
  290. };
  291. // append fun.instructions to the program and record that `fun.address` has been inserted
  292. // at `start_ins`. We'll use `start_ins` to do pc-relative calls.
  293. let start_ins = program.instructions.len();
  294. program.instructions.extend(&fun.instructions);
  295. debug!(
  296. "linked function `{}` at instruction {}",
  297. fun.name, start_ins
  298. );
  299. // link func and line info into the main program
  300. // the offset needs to be adjusted
  301. self.link_func_and_line_info(program, fun, start_ins)?;
  302. self.linked_functions.insert(fun.address, start_ins);
  303. // relocate `fun`, recursively linking in all the callees
  304. self.relocate(program, fun)?;
  305. Ok(start_ins)
  306. }
  307. fn relocate(&mut self, program: &mut Function, fun: &Function) -> Result<(), RelocationError> {
  308. let relocations = self.relocations.get(&fun.section_index);
  309. let n_instructions = fun.instructions.len();
  310. let start_ins = program.instructions.len() - n_instructions;
  311. debug!(
  312. "relocating program `{}` function `{}` size {}",
  313. program.name, fun.name, n_instructions
  314. );
  315. // process all the instructions. We can't only loop over relocations since we need to
  316. // patch pc-relative calls too.
  317. for ins_index in start_ins..start_ins + n_instructions {
  318. let ins = program.instructions[ins_index];
  319. let is_call = insn_is_call(&ins);
  320. let rel = relocations
  321. .and_then(|relocations| {
  322. relocations
  323. .get(&((fun.section_offset + (ins_index - start_ins) * INS_SIZE) as u64))
  324. })
  325. .and_then(|rel| {
  326. // get the symbol for the relocation
  327. self.symbol_table
  328. .get(&rel.symbol_index)
  329. .map(|sym| (rel, sym))
  330. })
  331. .filter(|(_rel, sym)| {
  332. // only consider text relocations, data relocations are
  333. // relocated in relocate_maps()
  334. sym.kind == SymbolKind::Text
  335. || sym
  336. .section_index
  337. .map(|section_index| self.text_sections.contains(&section_index))
  338. .unwrap_or(false)
  339. });
  340. // not a call and not a text relocation, we don't need to do anything
  341. if !is_call && rel.is_none() {
  342. continue;
  343. }
  344. let (callee_section_index, callee_address) = if let Some((rel, sym)) = rel {
  345. let address = match sym.kind {
  346. SymbolKind::Text => sym.address,
  347. // R_BPF_64_32 this is a call
  348. SymbolKind::Section if rel.size == 32 => {
  349. sym.address + (ins.imm + 1) as u64 * INS_SIZE as u64
  350. }
  351. // R_BPF_64_64 this is a ld_imm64 text relocation
  352. SymbolKind::Section if rel.size == 64 => sym.address + ins.imm as u64,
  353. _ => todo!(), // FIXME: return an error here,
  354. };
  355. (sym.section_index.unwrap(), address)
  356. } else {
  357. // The caller and the callee are in the same ELF section and this is a pc-relative
  358. // call. Resolve the pc-relative imm to an absolute address.
  359. let ins_size = INS_SIZE as i64;
  360. (
  361. fun.section_index.0,
  362. (fun.section_offset as i64
  363. + ((ins_index - start_ins) as i64) * ins_size
  364. + (ins.imm + 1) as i64 * ins_size) as u64,
  365. )
  366. };
  367. debug!(
  368. "relocating {} to callee address {:#x} in section {} ({}) at instruction {ins_index}",
  369. if is_call { "call" } else { "reference" },
  370. callee_address,
  371. callee_section_index,
  372. if rel.is_some() {
  373. "relocation"
  374. } else {
  375. "pc-relative"
  376. },
  377. );
  378. // lookup and link the callee if it hasn't been linked already. `callee_ins_index` will
  379. // contain the instruction index of the callee inside the program.
  380. let callee = self
  381. .functions
  382. .get(&(callee_section_index, callee_address))
  383. .ok_or(RelocationError::UnknownFunction {
  384. address: callee_address,
  385. caller_name: fun.name.clone(),
  386. })?;
  387. debug!("callee is `{}`", callee.name);
  388. let callee_ins_index = self.link_function(program, callee)? as i32;
  389. let ins = &mut program.instructions[ins_index];
  390. let ins_index = ins_index as i32;
  391. ins.imm = callee_ins_index - ins_index - 1;
  392. debug!(
  393. "callee `{}` is at ins {callee_ins_index}, {} from current instruction {ins_index}",
  394. callee.name, ins.imm
  395. );
  396. if !is_call {
  397. ins.set_src_reg(BPF_PSEUDO_FUNC as u8);
  398. }
  399. }
  400. debug!(
  401. "finished relocating program `{}` function `{}`",
  402. program.name, fun.name
  403. );
  404. Ok(())
  405. }
  406. fn link_func_and_line_info(
  407. &mut self,
  408. program: &mut Function,
  409. fun: &Function,
  410. start: usize,
  411. ) -> Result<(), RelocationError> {
  412. let func_info = &fun.func_info.func_info;
  413. let func_info = func_info.iter().cloned().map(|mut info| {
  414. // `start` is the new instruction offset of `fun` within `program`
  415. info.insn_off = start as u32;
  416. info
  417. });
  418. program.func_info.func_info.extend(func_info);
  419. program.func_info.num_info = program.func_info.func_info.len() as u32;
  420. let line_info = &fun.line_info.line_info;
  421. if !line_info.is_empty() {
  422. // this is the original offset
  423. let original_start_off = line_info[0].insn_off;
  424. let line_info = line_info.iter().cloned().map(|mut info| {
  425. // rebase offsets on top of start, which is the offset of the
  426. // function in the program being linked
  427. info.insn_off = start as u32 + (info.insn_off - original_start_off);
  428. info
  429. });
  430. program.line_info.line_info.extend(line_info);
  431. program.line_info.num_info = program.func_info.func_info.len() as u32;
  432. }
  433. Ok(())
  434. }
  435. }
  436. fn insn_is_call(ins: &bpf_insn) -> bool {
  437. let klass = (ins.code & 0x07) as u32;
  438. let op = (ins.code & 0xF0) as u32;
  439. let src = (ins.code & 0x08) as u32;
  440. klass == BPF_JMP
  441. && op == BPF_CALL
  442. && src == BPF_K
  443. && ins.src_reg() as u32 == BPF_PSEUDO_CALL
  444. && ins.dst_reg() == 0
  445. && ins.off == 0
  446. }
  447. #[cfg(test)]
  448. mod test {
  449. use alloc::{string::ToString, vec, vec::Vec};
  450. use crate::{
  451. maps::{BtfMap, LegacyMap, Map},
  452. BpfSectionKind,
  453. };
  454. use super::*;
  455. fn fake_sym(index: usize, section_index: usize, address: u64, name: &str, size: u64) -> Symbol {
  456. Symbol {
  457. index,
  458. section_index: Some(section_index),
  459. name: Some(name.to_string()),
  460. address,
  461. size,
  462. is_definition: false,
  463. kind: SymbolKind::Data,
  464. }
  465. }
  466. fn ins(bytes: &[u8]) -> bpf_insn {
  467. unsafe { core::ptr::read_unaligned(bytes.as_ptr() as *const _) }
  468. }
  469. fn fake_legacy_map(symbol_index: usize) -> Map {
  470. Map::Legacy(LegacyMap {
  471. def: Default::default(),
  472. section_index: 0,
  473. section_kind: BpfSectionKind::Undefined,
  474. symbol_index: Some(symbol_index),
  475. data: Vec::new(),
  476. })
  477. }
  478. fn fake_btf_map(symbol_index: usize) -> Map {
  479. Map::Btf(BtfMap {
  480. def: Default::default(),
  481. section_index: 0,
  482. symbol_index,
  483. data: Vec::new(),
  484. })
  485. }
  486. fn fake_func(name: &str, instructions: Vec<bpf_insn>) -> Function {
  487. Function {
  488. address: Default::default(),
  489. name: name.to_string(),
  490. section_index: SectionIndex(0),
  491. section_offset: Default::default(),
  492. instructions,
  493. func_info: Default::default(),
  494. line_info: Default::default(),
  495. func_info_rec_size: Default::default(),
  496. line_info_rec_size: Default::default(),
  497. }
  498. }
  499. #[test]
  500. fn test_single_legacy_map_relocation() {
  501. let mut fun = fake_func(
  502. "test",
  503. vec![ins(&[
  504. 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  505. 0x00, 0x00,
  506. ])],
  507. );
  508. let symbol_table = HashMap::from([(1, fake_sym(1, 0, 0, "test_map", 0))]);
  509. let relocations = vec![Relocation {
  510. offset: 0x0,
  511. symbol_index: 1,
  512. size: 64,
  513. }];
  514. let maps_by_section = HashMap::new();
  515. let map = fake_legacy_map(1);
  516. let maps_by_symbol = HashMap::from([(1, ("test_map", Some(1), &map))]);
  517. relocate_maps(
  518. &mut fun,
  519. relocations.iter(),
  520. &maps_by_section,
  521. &maps_by_symbol,
  522. &symbol_table,
  523. &HashSet::new(),
  524. )
  525. .unwrap();
  526. assert_eq!(fun.instructions[0].src_reg(), BPF_PSEUDO_MAP_FD as u8);
  527. assert_eq!(fun.instructions[0].imm, 1);
  528. }
  529. #[test]
  530. fn test_multiple_legacy_map_relocation() {
  531. let mut fun = fake_func(
  532. "test",
  533. vec![
  534. ins(&[
  535. 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  536. 0x00, 0x00, 0x00,
  537. ]),
  538. ins(&[
  539. 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  540. 0x00, 0x00, 0x00,
  541. ]),
  542. ],
  543. );
  544. let symbol_table = HashMap::from([
  545. (1, fake_sym(1, 0, 0, "test_map_1", 0)),
  546. (2, fake_sym(2, 0, 0, "test_map_2", 0)),
  547. ]);
  548. let relocations = vec![
  549. Relocation {
  550. offset: 0x0,
  551. symbol_index: 1,
  552. size: 64,
  553. },
  554. Relocation {
  555. offset: mem::size_of::<bpf_insn>() as u64,
  556. symbol_index: 2,
  557. size: 64,
  558. },
  559. ];
  560. let maps_by_section = HashMap::new();
  561. let map_1 = fake_legacy_map(1);
  562. let map_2 = fake_legacy_map(2);
  563. let maps_by_symbol = HashMap::from([
  564. (1, ("test_map_1", Some(1), &map_1)),
  565. (2, ("test_map_2", Some(2), &map_2)),
  566. ]);
  567. relocate_maps(
  568. &mut fun,
  569. relocations.iter(),
  570. &maps_by_section,
  571. &maps_by_symbol,
  572. &symbol_table,
  573. &HashSet::new(),
  574. )
  575. .unwrap();
  576. assert_eq!(fun.instructions[0].src_reg(), BPF_PSEUDO_MAP_FD as u8);
  577. assert_eq!(fun.instructions[0].imm, 1);
  578. assert_eq!(fun.instructions[1].src_reg(), BPF_PSEUDO_MAP_FD as u8);
  579. assert_eq!(fun.instructions[1].imm, 2);
  580. }
  581. #[test]
  582. fn test_single_btf_map_relocation() {
  583. let mut fun = fake_func(
  584. "test",
  585. vec![ins(&[
  586. 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  587. 0x00, 0x00,
  588. ])],
  589. );
  590. let symbol_table = HashMap::from([(1, fake_sym(1, 0, 0, "test_map", 0))]);
  591. let relocations = vec![Relocation {
  592. offset: 0x0,
  593. symbol_index: 1,
  594. size: 64,
  595. }];
  596. let maps_by_section = HashMap::new();
  597. let map = fake_btf_map(1);
  598. let maps_by_symbol = HashMap::from([(1, ("test_map", Some(1), &map))]);
  599. relocate_maps(
  600. &mut fun,
  601. relocations.iter(),
  602. &maps_by_section,
  603. &maps_by_symbol,
  604. &symbol_table,
  605. &HashSet::new(),
  606. )
  607. .unwrap();
  608. assert_eq!(fun.instructions[0].src_reg(), BPF_PSEUDO_MAP_FD as u8);
  609. assert_eq!(fun.instructions[0].imm, 1);
  610. }
  611. #[test]
  612. fn test_multiple_btf_map_relocation() {
  613. let mut fun = fake_func(
  614. "test",
  615. vec![
  616. ins(&[
  617. 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  618. 0x00, 0x00, 0x00,
  619. ]),
  620. ins(&[
  621. 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  622. 0x00, 0x00, 0x00,
  623. ]),
  624. ],
  625. );
  626. let symbol_table = HashMap::from([
  627. (1, fake_sym(1, 0, 0, "test_map_1", 0)),
  628. (2, fake_sym(2, 0, 0, "test_map_2", 0)),
  629. ]);
  630. let relocations = vec![
  631. Relocation {
  632. offset: 0x0,
  633. symbol_index: 1,
  634. size: 64,
  635. },
  636. Relocation {
  637. offset: mem::size_of::<bpf_insn>() as u64,
  638. symbol_index: 2,
  639. size: 64,
  640. },
  641. ];
  642. let maps_by_section = HashMap::new();
  643. let map_1 = fake_btf_map(1);
  644. let map_2 = fake_btf_map(2);
  645. let maps_by_symbol = HashMap::from([
  646. (1, ("test_map_1", Some(1), &map_1)),
  647. (2, ("test_map_2", Some(2), &map_2)),
  648. ]);
  649. relocate_maps(
  650. &mut fun,
  651. relocations.iter(),
  652. &maps_by_section,
  653. &maps_by_symbol,
  654. &symbol_table,
  655. &HashSet::new(),
  656. )
  657. .unwrap();
  658. assert_eq!(fun.instructions[0].src_reg(), BPF_PSEUDO_MAP_FD as u8);
  659. assert_eq!(fun.instructions[0].imm, 1);
  660. assert_eq!(fun.instructions[1].src_reg(), BPF_PSEUDO_MAP_FD as u8);
  661. assert_eq!(fun.instructions[1].imm, 2);
  662. }
  663. }