Explorar el Código

Support non-native endianness

Alessandro Decina hace 4 años
padre
commit
65d520bbd7
Se han modificado 4 ficheros con 60 adiciones y 20 borrados
  1. 40 14
      src/obj/btf/btf.rs
  2. 9 1
      src/obj/btf/relocation.rs
  3. 9 3
      src/obj/btf/types.rs
  4. 2 2
      src/obj/mod.rs

+ 40 - 14
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<u8>,
     types: Vec<BtfType>,
+    endianness: Endianness,
 }
 
 impl Btf {
-    pub(crate) fn parse(data: &[u8]) -> Result<Btf, BtfError> {
+    pub(crate) fn parse(data: &[u8], endianness: Endianness) -> Result<Btf, BtfError> {
         if data.len() < mem::size_of::<btf_header>() {
             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<Vec<BtfType>, BtfError> {
+    fn read_type_info(
+        header: &btf_header,
+        data: &[u8],
+        endianness: Endianness,
+    ) -> Result<Vec<BtfType>, 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<u8>,
+    endianness: Endianness,
     relocations: Vec<(u32, Vec<Relocation>)>,
     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<BtfExt, BtfError> {
+    pub(crate) fn parse(data: &[u8], endianness: Endianness) -> Result<BtfExt, BtfError> {
         // Safety: btf_ext_header is POD so read_unaligned is safe
         let header = unsafe {
             ptr::read_unaligned::<btf_ext_header>(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<Item = &(u32, Vec<Relocation>)> {
@@ -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;

+ 9 - 1
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::<u32, Vec<Candidate>>::new();
 

+ 9 - 3
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<T>(data: &[u8], len: usize) -> Result<Vec<T>, BtfError> {
 
 impl BtfType {
     #[allow(unused_unsafe)]
-    pub(crate) unsafe fn read(data: &[u8]) -> Result<BtfType, BtfError> {
+    pub(crate) unsafe fn read(data: &[u8], endianness: Endianness) -> Result<BtfType, BtfError> {
         let ty = unsafe { read::<btf_type>(data)? };
         let data = &data[mem::size_of::<btf_type>()..];
 
@@ -120,13 +122,17 @@ impl BtfType {
             BtfKind::Typedef => Typedef(ty),
             BtfKind::Func => Func(ty),
             BtfKind::Int => {
-                // FIXME: endianness
                 if mem::size_of::<u32>() > 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::<u32>()].try_into().unwrap()),
+                    read_u32(data[..mem::size_of::<u32>()].try_into().unwrap()),
                 )
             }
             BtfKind::Enum => Enum(ty, unsafe { read_array(data, vlen)? }),

+ 2 - 2
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(())
     }