Support non-native endianness

pull/1/head
Alessandro Decina 4 years ago
parent 5b8def7b69
commit 65d520bbd7

@ -5,6 +5,7 @@ use std::{
mem, ptr, mem, ptr,
}; };
use object::Endianness;
use thiserror::Error; use thiserror::Error;
use crate::generated::{btf_ext_header, btf_header}; use crate::generated::{btf_ext_header, btf_header};
@ -63,10 +64,11 @@ pub struct Btf {
header: btf_header, header: btf_header,
strings: Vec<u8>, strings: Vec<u8>,
types: Vec<BtfType>, types: Vec<BtfType>,
endianness: Endianness,
} }
impl Btf { 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>() { if data.len() < mem::size_of::<btf_header>() {
return Err(BtfError::InvalidHeader); return Err(BtfError::InvalidHeader);
} }
@ -81,16 +83,21 @@ impl Btf {
} }
let strings = data[str_off..str_off + str_len].to_vec(); 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 { Ok(Btf {
header, header,
strings, strings,
types, 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 hdr_len = header.hdr_len as usize;
let type_off = header.type_off as usize; let type_off = header.type_off as usize;
let type_len = header.type_len as usize; let type_len = header.type_len as usize;
@ -105,7 +112,7 @@ impl Btf {
// Safety: // Safety:
// read() reads POD values from ELF, which is sound, but the values can still contain // 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). // 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()..]; data = &data[ty.type_info_size()..];
types.push(ty); types.push(ty);
} }
@ -221,6 +228,7 @@ impl Btf {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct BtfExt { pub struct BtfExt {
data: Vec<u8>, data: Vec<u8>,
endianness: Endianness,
relocations: Vec<(u32, Vec<Relocation>)>, relocations: Vec<(u32, Vec<Relocation>)>,
header: btf_ext_header, header: btf_ext_header,
func_info_rec_size: usize, func_info_rec_size: usize,
@ -229,7 +237,7 @@ pub struct BtfExt {
} }
impl 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 // Safety: btf_ext_header is POD so read_unaligned is safe
let header = unsafe { let header = unsafe {
ptr::read_unaligned::<btf_ext_header>(data.as_ptr() as *const btf_ext_header) ptr::read_unaligned::<btf_ext_header>(data.as_ptr() as *const btf_ext_header)
@ -246,9 +254,13 @@ impl BtfExt {
section_len: data.len(), section_len: data.len(),
}); });
} }
let read_u32 = if endianness == Endianness::Little {
u32::from_le_bytes
} else {
u32::from_be_bytes
};
Ok(if len > 0 { Ok(if len > 0 {
/* FIXME: endianness */ read_u32(data[offset..offset + 4].try_into().unwrap()) as usize
u32::from_ne_bytes(data[offset..offset + 4].try_into().unwrap()) as usize
} else { } else {
0 0
}) })
@ -271,11 +283,12 @@ impl BtfExt {
line_info_rec_size: rec_size(line_info_off, line_info_len)?, line_info_rec_size: rec_size(line_info_off, line_info_len)?,
core_relo_rec_size: rec_size(core_relo_off, core_relo_len)?, core_relo_rec_size: rec_size(core_relo_off, core_relo_len)?,
data: data.to_vec(), data: data.to_vec(),
endianness,
}; };
let rec_size = ext.core_relo_rec_size; let rec_size = ext.core_relo_rec_size;
ext.relocations.extend( 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| { .map(move |sec| {
let relos = sec let relos = sec
.data .data
@ -315,11 +328,19 @@ impl BtfExt {
} }
pub(crate) fn func_info(&self) -> SecInfoIter<'_> { 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<'_> { 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>)> { pub(crate) fn relocations(&self) -> impl Iterator<Item = &(u32, Vec<Relocation>)> {
@ -331,14 +352,16 @@ pub(crate) struct SecInfoIter<'a> {
data: &'a [u8], data: &'a [u8],
offset: usize, offset: usize,
rec_size: usize, rec_size: usize,
endianness: Endianness,
} }
impl<'a> SecInfoIter<'a> { 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 { Self {
data, data,
rec_size, rec_size,
offset: 0, offset: 0,
endianness,
} }
} }
} }
@ -352,9 +375,12 @@ impl<'a> Iterator for SecInfoIter<'a> {
return None; return None;
} }
// FIXME: endianness let read_u32 = if self.endianness == Endianness::Little {
let sec_name_off = u32::from_le_bytes
u32::from_ne_bytes(data[self.offset..self.offset + 4].try_into().unwrap()); } else {
u32::from_be_bytes
};
let sec_name_off = read_u32(data[self.offset..self.offset + 4].try_into().unwrap());
self.offset += 4; self.offset += 4;
let num_info = u32::from_ne_bytes(data[self.offset..self.offset + 4].try_into().unwrap()); let num_info = u32::from_ne_bytes(data[self.offset..self.offset + 4].try_into().unwrap());
self.offset += 4; self.offset += 4;

@ -4,6 +4,7 @@ use std::{
fs, io, mem, ptr, fs, io, mem, ptr,
}; };
use object::{Endian, Endianness, NativeEndian};
use thiserror::Error; use thiserror::Error;
use crate::{ use crate::{
@ -167,7 +168,14 @@ impl Object {
}; };
let target_btf = fs::read("/sys/kernel/btf/vmlinux")?; 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(); let mut candidates_cache = HashMap::<u32, Vec<Candidate>>::new();

@ -3,6 +3,8 @@ use std::{
mem, ptr, mem, ptr,
}; };
use object::Endianness;
use crate::{ use crate::{
generated::{ generated::{
btf_array, btf_enum, btf_member, btf_param, btf_type, btf_type__bindgen_ty_1, btf_var, 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 { impl BtfType {
#[allow(unused_unsafe)] #[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 ty = unsafe { read::<btf_type>(data)? };
let data = &data[mem::size_of::<btf_type>()..]; let data = &data[mem::size_of::<btf_type>()..];
@ -120,13 +122,17 @@ impl BtfType {
BtfKind::Typedef => Typedef(ty), BtfKind::Typedef => Typedef(ty),
BtfKind::Func => Func(ty), BtfKind::Func => Func(ty),
BtfKind::Int => { BtfKind::Int => {
// FIXME: endianness
if mem::size_of::<u32>() > data.len() { if mem::size_of::<u32>() > data.len() {
return Err(BtfError::InvalidTypeInfo); return Err(BtfError::InvalidTypeInfo);
} }
let read_u32 = if endianness == Endianness::Little {
u32::from_le_bytes
} else {
u32::from_be_bytes
};
Int( Int(
ty, 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)? }), BtfKind::Enum => Enum(ty, unsafe { read_array(data, vlen)? }),

@ -162,13 +162,13 @@ impl Object {
} }
fn parse_btf(&mut self, section: &Section) -> Result<(), BtfError> { 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(()) Ok(())
} }
fn parse_btf_ext(&mut self, section: &Section) -> Result<(), BtfError> { 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(()) Ok(())
} }

Loading…
Cancel
Save