From 65d520bbd79a4c84d4dbc7f1b8fa8d3b75f4dc7d Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Fri, 5 Feb 2021 19:43:53 +0000 Subject: [PATCH] Support non-native endianness --- src/obj/btf/btf.rs | 54 +++++++++++++++++++++++++++++---------- src/obj/btf/relocation.rs | 10 +++++++- src/obj/btf/types.rs | 12 ++++++--- src/obj/mod.rs | 4 +-- 4 files changed, 60 insertions(+), 20 deletions(-) diff --git a/src/obj/btf/btf.rs b/src/obj/btf/btf.rs index e15e3391..301c69d5 100644 --- a/src/obj/btf/btf.rs +++ b/src/obj/btf/btf.rs @@ -5,6 +5,7 @@ use std::{ mem, ptr, }; +use object::Endianness; use thiserror::Error; use crate::generated::{btf_ext_header, btf_header}; @@ -63,10 +64,11 @@ pub struct Btf { header: btf_header, strings: Vec, types: Vec, + endianness: Endianness, } impl Btf { - pub(crate) fn parse(data: &[u8]) -> Result { + pub(crate) fn parse(data: &[u8], endianness: Endianness) -> Result { if data.len() < mem::size_of::() { return Err(BtfError::InvalidHeader); } @@ -81,16 +83,21 @@ impl Btf { } let strings = data[str_off..str_off + str_len].to_vec(); - let types = Btf::read_type_info(&header, data)?; + let types = Btf::read_type_info(&header, data, endianness)?; Ok(Btf { header, strings, types, + endianness, }) } - fn read_type_info(header: &btf_header, data: &[u8]) -> Result, BtfError> { + fn read_type_info( + header: &btf_header, + data: &[u8], + endianness: Endianness, + ) -> Result, BtfError> { let hdr_len = header.hdr_len as usize; let type_off = header.type_off as usize; let type_len = header.type_len as usize; @@ -105,7 +112,7 @@ impl Btf { // Safety: // read() reads POD values from ELF, which is sound, but the values can still contain // internally inconsistent values (like out of bound offsets and such). - let ty = unsafe { BtfType::read(data)? }; + let ty = unsafe { BtfType::read(data, endianness)? }; data = &data[ty.type_info_size()..]; types.push(ty); } @@ -221,6 +228,7 @@ impl Btf { #[derive(Debug, Clone)] pub struct BtfExt { data: Vec, + endianness: Endianness, relocations: Vec<(u32, Vec)>, header: btf_ext_header, func_info_rec_size: usize, @@ -229,7 +237,7 @@ pub struct BtfExt { } impl BtfExt { - pub(crate) fn parse(data: &[u8]) -> Result { + pub(crate) fn parse(data: &[u8], endianness: Endianness) -> Result { // Safety: btf_ext_header is POD so read_unaligned is safe let header = unsafe { ptr::read_unaligned::(data.as_ptr() as *const btf_ext_header) @@ -246,9 +254,13 @@ impl BtfExt { section_len: data.len(), }); } + let read_u32 = if endianness == Endianness::Little { + u32::from_le_bytes + } else { + u32::from_be_bytes + }; Ok(if len > 0 { - /* FIXME: endianness */ - u32::from_ne_bytes(data[offset..offset + 4].try_into().unwrap()) as usize + read_u32(data[offset..offset + 4].try_into().unwrap()) as usize } else { 0 }) @@ -271,11 +283,12 @@ impl BtfExt { line_info_rec_size: rec_size(line_info_off, line_info_len)?, core_relo_rec_size: rec_size(core_relo_off, core_relo_len)?, data: data.to_vec(), + endianness, }; let rec_size = ext.core_relo_rec_size; ext.relocations.extend( - SecInfoIter::new(ext.core_relo_data(), ext.core_relo_rec_size) + SecInfoIter::new(ext.core_relo_data(), ext.core_relo_rec_size, endianness) .map(move |sec| { let relos = sec .data @@ -315,11 +328,19 @@ impl BtfExt { } pub(crate) fn func_info(&self) -> SecInfoIter<'_> { - SecInfoIter::new(self.func_info_data(), self.func_info_rec_size) + SecInfoIter::new( + self.func_info_data(), + self.func_info_rec_size, + self.endianness, + ) } pub(crate) fn line_info(&self) -> SecInfoIter<'_> { - SecInfoIter::new(self.line_info_data(), self.line_info_rec_size) + SecInfoIter::new( + self.line_info_data(), + self.line_info_rec_size, + self.endianness, + ) } pub(crate) fn relocations(&self) -> impl Iterator)> { @@ -331,14 +352,16 @@ pub(crate) struct SecInfoIter<'a> { data: &'a [u8], offset: usize, rec_size: usize, + endianness: Endianness, } impl<'a> SecInfoIter<'a> { - fn new(data: &'a [u8], rec_size: usize) -> Self { + fn new(data: &'a [u8], rec_size: usize, endianness: Endianness) -> Self { Self { data, rec_size, offset: 0, + endianness, } } } @@ -352,9 +375,12 @@ impl<'a> Iterator for SecInfoIter<'a> { return None; } - // FIXME: endianness - let sec_name_off = - u32::from_ne_bytes(data[self.offset..self.offset + 4].try_into().unwrap()); + let read_u32 = if self.endianness == Endianness::Little { + u32::from_le_bytes + } else { + u32::from_be_bytes + }; + let sec_name_off = read_u32(data[self.offset..self.offset + 4].try_into().unwrap()); self.offset += 4; let num_info = u32::from_ne_bytes(data[self.offset..self.offset + 4].try_into().unwrap()); self.offset += 4; diff --git a/src/obj/btf/relocation.rs b/src/obj/btf/relocation.rs index 77485b92..8aa2d2c9 100644 --- a/src/obj/btf/relocation.rs +++ b/src/obj/btf/relocation.rs @@ -4,6 +4,7 @@ use std::{ fs, io, mem, ptr, }; +use object::{Endian, Endianness, NativeEndian}; use thiserror::Error; use crate::{ @@ -167,7 +168,14 @@ impl Object { }; let target_btf = fs::read("/sys/kernel/btf/vmlinux")?; - let target_btf = Btf::parse(&target_btf)?; + let target_btf = Btf::parse(&target_btf, { + let e = NativeEndian; + if e.is_little_endian() { + Endianness::Little + } else { + Endianness::Big + } + })?; let mut candidates_cache = HashMap::>::new(); diff --git a/src/obj/btf/types.rs b/src/obj/btf/types.rs index 87b9c76d..c2576b9d 100644 --- a/src/obj/btf/types.rs +++ b/src/obj/btf/types.rs @@ -3,6 +3,8 @@ use std::{ mem, ptr, }; +use object::Endianness; + use crate::{ generated::{ btf_array, btf_enum, btf_member, btf_param, btf_type, btf_type__bindgen_ty_1, btf_var, @@ -104,7 +106,7 @@ unsafe fn read_array(data: &[u8], len: usize) -> Result, BtfError> { impl BtfType { #[allow(unused_unsafe)] - pub(crate) unsafe fn read(data: &[u8]) -> Result { + pub(crate) unsafe fn read(data: &[u8], endianness: Endianness) -> Result { let ty = unsafe { read::(data)? }; let data = &data[mem::size_of::()..]; @@ -120,13 +122,17 @@ impl BtfType { BtfKind::Typedef => Typedef(ty), BtfKind::Func => Func(ty), BtfKind::Int => { - // FIXME: endianness if mem::size_of::() > data.len() { return Err(BtfError::InvalidTypeInfo); } + let read_u32 = if endianness == Endianness::Little { + u32::from_le_bytes + } else { + u32::from_be_bytes + }; Int( ty, - u32::from_ne_bytes(data[..mem::size_of::()].try_into().unwrap()), + read_u32(data[..mem::size_of::()].try_into().unwrap()), ) } BtfKind::Enum => Enum(ty, unsafe { read_array(data, vlen)? }), diff --git a/src/obj/mod.rs b/src/obj/mod.rs index 9a91e3d7..c2977ad4 100644 --- a/src/obj/mod.rs +++ b/src/obj/mod.rs @@ -162,13 +162,13 @@ impl Object { } fn parse_btf(&mut self, section: &Section) -> Result<(), BtfError> { - self.btf = Some(Btf::parse(section.data)?); + 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.btf_ext = Some(BtfExt::parse(section.data, self.endianness)?); Ok(()) }