aya: Improved BTF Type API

This commit removes reliance on generated BtfType structs, as
well as adding a dedicated struct for each BTF type. As such,
we can now add nice accessors like `bits()` and `encoding()`
for Int vs. inlined shift/mask operations.

Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
pull/285/head
Dave Tucker 2 years ago
parent 906c25ff23
commit f34ebeba99

@ -1,7 +1,8 @@
use std::{
borrow::Cow,
collections::HashMap,
ffi::{c_void, CStr, CString},
convert::TryInto,
ffi::{CStr, CString},
fs, io, mem,
path::{Path, PathBuf},
ptr,
@ -14,17 +15,17 @@ use object::Endianness;
use thiserror::Error;
use crate::{
generated::{btf_enum, btf_ext_header, btf_func_linkage, btf_header, btf_member},
obj::btf::{relocation::Relocation, BtfKind, BtfType},
generated::{btf_ext_header, btf_header},
obj::btf::{
info::{FuncSecInfo, LineSecInfo},
relocation::Relocation,
Array, BtfEnum, BtfKind, BtfMember, BtfType, Const, Enum, FuncInfo, FuncLinkage, Int,
IntEncoding, LineInfo, Struct, Typedef, VarLinkage,
},
util::bytes_of,
Features,
};
use super::{
info::{FuncSecInfo, LineSecInfo},
type_vlen, FuncInfo, LineInfo,
};
pub(crate) const MAX_RESOLVE_DEPTH: u8 = 32;
pub(crate) const MAX_SPEC_LEN: usize = 64;
@ -198,16 +199,16 @@ impl Btf {
pub(crate) fn add_string(&mut self, name: String) -> u32 {
let str = CString::new(name).unwrap();
let name_off = self.strings.len();
let name_offset = self.strings.len();
self.strings.extend(str.as_c_str().to_bytes_with_nul());
self.header.str_len = self.strings.len() as u32;
name_off as u32
name_offset as u32
}
pub(crate) fn add_type(&mut self, type_: BtfType) -> u32 {
let size = type_.type_info_size() as u32;
pub(crate) fn add_type(&mut self, btf_type: BtfType) -> u32 {
let size = btf_type.type_info_size() as u32;
let type_id = self.types.len();
self.types.push(type_);
self.types.push(btf_type);
self.header.type_len += size;
self.header.str_off += size;
type_id as u32
@ -315,36 +316,24 @@ impl Btf {
self.types.resolve_type(root_type_id)
}
pub(crate) fn type_name(&self, ty: &BtfType) -> Result<Option<Cow<'_, str>>, BtfError> {
ty.name_offset().map(|off| self.string_at(off)).transpose()
pub(crate) fn type_name(&self, ty: &BtfType) -> Result<Cow<'_, str>, BtfError> {
self.string_at(ty.name_offset())
}
pub(crate) fn err_type_name(&self, ty: &BtfType) -> Option<String> {
ty.name_offset()
.and_then(|off| self.string_at(off).ok().map(String::from))
self.string_at(ty.name_offset()).ok().map(String::from)
}
pub(crate) fn id_by_type_name_kind(&self, name: &str, kind: BtfKind) -> Result<u32, BtfError> {
for (type_id, ty) in self.types().enumerate() {
match ty.kind()? {
Some(k) => {
if k != kind {
if ty.kind() != kind {
continue;
}
}
None => continue,
}
match self.type_name(ty)? {
Some(ty_name) => {
if ty_name == name {
if self.type_name(ty)? == name {
return Ok(type_id as u32);
}
continue;
}
None => continue,
}
}
Err(BtfError::UnknownBtfTypeName {
type_name: name.to_string(),
@ -356,41 +345,24 @@ impl Btf {
let mut n_elems = 1;
for _ in 0..MAX_RESOLVE_DEPTH {
let ty = self.types.type_by_id(type_id)?;
use BtfType::*;
let size = match ty {
Int(ty, _)
| Struct(ty, _)
| Union(ty, _)
| Enum(ty, _)
| DataSec(ty, _)
| Float(ty) => {
// Safety: union
unsafe { ty.__bindgen_anon_1.size as usize }
}
Ptr(_) => mem::size_of::<*const c_void>(), // FIXME
Typedef(ty)
| Volatile(ty)
| Const(ty)
| Restrict(ty)
| Var(ty, _)
| DeclTag(ty, _)
| TypeTag(ty) => {
// Safety: union
type_id = unsafe { ty.__bindgen_anon_1.type_ };
BtfType::Array(Array { array, .. }) => {
n_elems = array.len;
type_id = array.element_type;
continue;
}
Array(_, array) => {
n_elems *= array.nelems as usize;
type_id = array.type_;
other => {
if let Some(size) = other.size() {
size
} else if let Some(next) = other.btf_type() {
type_id = next;
continue;
} else {
return Err(BtfError::UnexpectedBtfType { type_id });
}
Unknown | Fwd(_) | Func(_) | FuncProto(_, _) => {
return Err(BtfError::UnexpectedBtfType { type_id })
}
};
return Ok(size * n_elems);
return Ok((size * n_elems) as usize);
}
Err(BtfError::MaximumTypeDepthReached {
@ -416,56 +388,55 @@ impl Btf {
let mut types = mem::take(&mut self.types);
for i in 0..types.types.len() {
let t = &types.types[i];
let kind = t.kind()?.unwrap_or_default();
let kind = t.kind();
match t {
// Fixup PTR for Rust
// LLVM emits names for Rust pointer types, which the kernel doesn't like
// While I figure out if this needs fixing in the Kernel or LLVM, we'll
// do a fixup here
BtfType::Ptr(ty) => {
let mut fixed_ty = *ty;
fixed_ty.name_off = 0;
BtfType::Ptr(ptr) => {
let mut fixed_ty = ptr.clone();
fixed_ty.name_offset = 0;
types.types[i] = BtfType::Ptr(fixed_ty)
}
// Sanitize VAR if they are not supported
BtfType::Var(ty, _) if !features.btf_datasec => {
types.types[i] = BtfType::new_int(ty.name_off, 1, 0, 0);
BtfType::Var(v) if !features.btf_datasec => {
types.types[i] = BtfType::Int(Int::new(v.name_offset, 1, IntEncoding::None, 0));
}
// Sanitize DATASEC if they are not supported
BtfType::DataSec(ty, data) if !features.btf_datasec => {
BtfType::DataSec(d) if !features.btf_datasec => {
debug!("{}: not supported. replacing with STRUCT", kind);
let mut members = vec![];
for member in data {
let mt = types.type_by_id(member.type_).unwrap();
members.push(btf_member {
name_off: mt.btf_type().unwrap().name_off,
type_: member.type_,
for member in d.entries.iter() {
let mt = types.type_by_id(member.btf_type).unwrap();
members.push(BtfMember {
name_offset: mt.name_offset(),
btf_type: member.btf_type,
offset: member.offset * 8,
})
}
types.types[i] = BtfType::new_struct(ty.name_off, members, 0);
types.types[i] = BtfType::Struct(Struct::new(t.name_offset(), members, 0));
}
// Fixup DATASEC
// DATASEC sizes aren't always set by LLVM
// we need to fix them here before loading the btf to the kernel
BtfType::DataSec(ty, data) if features.btf_datasec => {
BtfType::DataSec(d) if features.btf_datasec => {
// Start DataSec Fixups
let sec_name = self.string_at(ty.name_off)?;
let sec_name = self.string_at(d.name_offset)?;
let name = sec_name.to_string();
let mut fixed_ty = *ty;
let mut fixed_data = data.clone();
let mut fixed_ty = d.clone();
// Handle any "/" characters in section names
// Example: "maps/hashmap"
let fixed_name = name.replace('/', ".");
if fixed_name != name {
fixed_ty.name_off = self.add_string(fixed_name);
fixed_ty.name_offset = self.add_string(fixed_name);
}
// There are some cases when the compiler does indeed populate the
// size
if unsafe { ty.__bindgen_anon_1.size > 0 } {
if t.size().unwrap() > 0 {
debug!("{} {}: size fixup not required", kind, name);
} else {
// We need to get the size of the section from the ELF file
@ -477,19 +448,19 @@ impl Btf {
}
})?;
debug!("{} {}: fixup size to {}", kind, name, size);
fixed_ty.__bindgen_anon_1.size = *size as u32;
fixed_ty.size = *size as u32;
// The Vec<btf_var_secinfo> contains BTF_KIND_VAR sections
// that need to have their offsets adjusted. To do this,
// we need to get the offset from the ELF file.
// This was also cached during initial parsing and
// we can query by name in symbol_offsets
for d in &mut fixed_data {
let var_type = types.type_by_id(d.type_)?;
let var_kind = var_type.kind()?.unwrap();
if let BtfType::Var(vty, var) = var_type {
let var_name = self.string_at(vty.name_off)?.to_string();
if var.linkage == btf_func_linkage::BTF_FUNC_STATIC as u32 {
for d in &mut fixed_ty.entries.iter_mut() {
let var_type = types.type_by_id(d.btf_type)?;
let var_kind = var_type.kind();
if let BtfType::Var(var) = var_type {
let var_name = self.string_at(var.name_offset)?.to_string();
if var.linkage == VarLinkage::Static {
debug!(
"{} {}: {} {}: fixup not required",
kind, name, var_kind, var_name
@ -512,68 +483,66 @@ impl Btf {
}
}
}
types.types[i] = BtfType::DataSec(fixed_ty, fixed_data);
types.types[i] = BtfType::DataSec(fixed_ty);
}
// Fixup FUNC_PROTO
BtfType::FuncProto(ty, params) if features.btf_func => {
let mut params = params.clone();
for (i, mut param) in params.iter_mut().enumerate() {
if param.name_off == 0 && param.type_ != 0 {
param.name_off = self.add_string(format!("param{}", i));
BtfType::FuncProto(ty) if features.btf_func => {
let mut ty = ty.clone();
for (i, mut param) in ty.params.iter_mut().enumerate() {
if param.name_offset == 0 && param.btf_type != 0 {
param.name_offset = self.add_string(format!("param{}", i));
}
}
types.types[i] = BtfType::FuncProto(*ty, params);
types.types[i] = BtfType::FuncProto(ty);
}
// Sanitize FUNC_PROTO
BtfType::FuncProto(ty, vars) if !features.btf_func => {
BtfType::FuncProto(ty) if !features.btf_func => {
debug!("{}: not supported. replacing with ENUM", kind);
let members: Vec<btf_enum> = vars
let members: Vec<BtfEnum> = ty
.params
.iter()
.map(|p| btf_enum {
name_off: p.name_off,
val: p.type_ as i32,
.map(|p| BtfEnum {
name_offset: p.name_offset,
value: p.btf_type as i32,
})
.collect();
let enum_type = BtfType::new_enum(ty.name_off, members);
let enum_type = BtfType::Enum(Enum::new(ty.name_offset, members));
types.types[i] = enum_type;
}
// Sanitize FUNC
BtfType::Func(ty) if !features.btf_func => {
debug!("{}: not supported. replacing with TYPEDEF", kind);
let typedef_type =
BtfType::new_typedef(ty.name_off, unsafe { ty.__bindgen_anon_1.type_ });
let typedef_type = BtfType::Typedef(Typedef::new(ty.name_offset, ty.btf_type));
types.types[i] = typedef_type;
}
// Sanitize BTF_FUNC_GLOBAL
BtfType::Func(ty) if !features.btf_func_global => {
let mut fixed_ty = *ty;
if type_vlen(ty) == btf_func_linkage::BTF_FUNC_GLOBAL as usize {
let mut fixed_ty = ty.clone();
if ty.linkage() == FuncLinkage::Global {
debug!(
"{}: BTF_FUNC_GLOBAL not supported. replacing with BTF_FUNC_STATIC",
kind
);
fixed_ty.info = (ty.info & 0xFFFF0000)
| (btf_func_linkage::BTF_FUNC_STATIC as u32) & 0xFFFF;
fixed_ty.set_linkage(FuncLinkage::Static);
}
types.types[i] = BtfType::Func(fixed_ty);
}
// Sanitize FLOAT
BtfType::Float(ty) if !features.btf_float => {
debug!("{}: not supported. replacing with STRUCT", kind);
let struct_ty =
BtfType::new_struct(0, vec![], unsafe { ty.__bindgen_anon_1.size });
let struct_ty = BtfType::Struct(Struct::new(0, vec![], ty.size));
types.types[i] = struct_ty;
}
// Sanitize DECL_TAG
BtfType::DeclTag(ty, _) if !features.btf_decl_tag => {
BtfType::DeclTag(ty) if !features.btf_decl_tag => {
debug!("{}: not supported. replacing with INT", kind);
let int_type = BtfType::new_int(ty.name_off, 1, 0, 0);
let int_type = BtfType::Int(Int::new(ty.name_offset, 1, IntEncoding::None, 0));
types.types[i] = int_type;
}
// Sanitize TYPE_TAG
BtfType::TypeTag(ty) if !features.btf_type_tag => {
debug!("{}: not supported. replacing with CONST", kind);
let const_type = BtfType::new_const(unsafe { ty.__bindgen_anon_1.type_ });
let const_type = BtfType::Const(Const::new(ty.btf_type));
types.types[i] = const_type;
}
// The type does not need fixing up or sanitization
@ -670,12 +639,12 @@ impl BtfExt {
SecInfoIter::new(ext.func_info_data(), ext.func_info_rec_size, endianness)
.map(move |sec| {
let name = btf
.string_at(sec.sec_name_off)
.string_at(sec.name_offset)
.ok()
.map(String::from)
.unwrap();
let info = FuncSecInfo::parse(
sec.sec_name_off,
sec.name_offset,
sec.num_info,
func_info_rec_size,
sec.data,
@ -691,12 +660,12 @@ impl BtfExt {
SecInfoIter::new(ext.line_info_data(), ext.line_info_rec_size, endianness)
.map(move |sec| {
let name = btf
.string_at(sec.sec_name_off)
.string_at(sec.name_offset)
.ok()
.map(String::from)
.unwrap();
let info = LineSecInfo::parse(
sec.sec_name_off,
sec.name_offset,
sec.num_info,
line_info_rec_size,
sec.data,
@ -717,7 +686,7 @@ impl BtfExt {
.enumerate()
.map(|(n, rec)| unsafe { Relocation::parse(rec, n) })
.collect::<Result<Vec<_>, _>>()?;
Ok((sec.sec_name_off, relos))
Ok((sec.name_offset, relos))
})
.collect::<Result<Vec<_>, _>>()?,
);
@ -793,7 +762,7 @@ impl<'a> Iterator for SecInfoIter<'a> {
} else {
u32::from_be_bytes
};
let sec_name_off = read_u32(data[self.offset..self.offset + 4].try_into().unwrap());
let name_offset = 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;
@ -802,7 +771,7 @@ impl<'a> Iterator for SecInfoIter<'a> {
self.offset += self.rec_size * num_info as usize;
Some(SecInfo {
sec_name_off,
name_offset,
num_info,
data,
})
@ -829,7 +798,7 @@ impl BtfTypes {
let mut buf = vec![];
for t in self.types.iter().skip(1) {
let b = t.to_bytes();
buf.put(b.as_slice())
buf.extend(b)
}
buf
}
@ -855,9 +824,24 @@ impl BtfTypes {
use BtfType::*;
match ty {
Volatile(ty) | Const(ty) | Restrict(ty) | Typedef(ty) | TypeTag(ty) => {
// Safety: union
type_id = unsafe { ty.__bindgen_anon_1.type_ };
Volatile(ty) => {
type_id = ty.btf_type;
continue;
}
Const(ty) => {
type_id = ty.btf_type;
continue;
}
Restrict(ty) => {
type_id = ty.btf_type;
continue;
}
Typedef(ty) => {
type_id = ty.btf_type;
continue;
}
TypeTag(ty) => {
type_id = ty.btf_type;
continue;
}
_ => return Ok(type_id),
@ -872,15 +856,15 @@ impl BtfTypes {
#[derive(Debug)]
pub(crate) struct SecInfo<'a> {
sec_name_off: u32,
name_offset: u32,
num_info: u32,
data: &'a [u8],
}
#[cfg(test)]
mod tests {
use crate::generated::{
btf_param, btf_var_secinfo, BTF_INT_SIGNED, BTF_VAR_GLOBAL_EXTERN, BTF_VAR_STATIC,
use crate::obj::btf::{
BtfParam, DataSec, DataSecEntry, DeclTag, Float, Func, FuncProto, Ptr, TypeTag, Var,
};
use super::*;
@ -976,11 +960,11 @@ mod tests {
fn test_write_btf() {
let mut btf = Btf::new();
let name_offset = btf.add_string("int".to_string());
let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0);
let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0));
btf.add_type(int_type);
let name_offset = btf.add_string("widget".to_string());
let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0);
let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0));
btf.add_type(int_type);
let btf_bytes = btf.to_bytes();
@ -1002,10 +986,15 @@ mod tests {
fn test_fixup_ptr() {
let mut btf = Btf::new();
let name_offset = btf.add_string("int".to_string());
let int_type_id = btf.add_type(BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0));
let int_type_id = btf.add_type(BtfType::Int(Int::new(
name_offset,
4,
IntEncoding::Signed,
0,
)));
let name_offset = btf.add_string("&mut int".to_string());
let ptr_type_id = btf.add_type(BtfType::new_ptr(name_offset, int_type_id));
let ptr_type_id = btf.add_type(BtfType::Ptr(Ptr::new(name_offset, int_type_id)));
let features = Features {
..Default::default()
@ -1015,9 +1004,9 @@ mod tests {
.unwrap();
if let BtfType::Ptr(fixed) = btf.type_by_id(ptr_type_id).unwrap() {
assert!(
fixed.name_off == 0,
fixed.name_offset == 0,
"expected offset 0, got {}",
fixed.name_off
fixed.name_offset
)
} else {
panic!("not a ptr")
@ -1031,10 +1020,19 @@ mod tests {
fn test_sanitize_var() {
let mut btf = Btf::new();
let name_offset = btf.add_string("int".to_string());
let int_type_id = btf.add_type(BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0));
let int_type_id = btf.add_type(BtfType::Int(Int::new(
name_offset,
4,
IntEncoding::Signed,
0,
)));
let name_offset = btf.add_string("&mut int".to_string());
let var_type_id = btf.add_type(BtfType::new_var(name_offset, int_type_id, BTF_VAR_STATIC));
let var_type_id = btf.add_type(BtfType::Var(Var::new(
name_offset,
int_type_id,
VarLinkage::Static,
)));
let features = Features {
btf_datasec: false,
@ -1043,8 +1041,8 @@ mod tests {
btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
.unwrap();
if let BtfType::Int(fixed, _) = btf.type_by_id(var_type_id).unwrap() {
assert!(fixed.name_off == name_offset)
if let BtfType::Int(fixed) = btf.type_by_id(var_type_id).unwrap() {
assert!(fixed.name_offset == name_offset)
} else {
panic!("not an int")
}
@ -1057,18 +1055,28 @@ mod tests {
fn test_sanitize_datasec() {
let mut btf = Btf::new();
let name_offset = btf.add_string("int".to_string());
let int_type_id = btf.add_type(BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0));
let int_type_id = btf.add_type(BtfType::Int(Int::new(
name_offset,
4,
IntEncoding::Signed,
0,
)));
let name_offset = btf.add_string("foo".to_string());
let var_type_id = btf.add_type(BtfType::new_var(name_offset, int_type_id, BTF_VAR_STATIC));
let var_type_id = btf.add_type(BtfType::Var(Var::new(
name_offset,
int_type_id,
VarLinkage::Static,
)));
let name_offset = btf.add_string(".data".to_string());
let variables = vec![btf_var_secinfo {
type_: var_type_id,
let variables = vec![DataSecEntry {
btf_type: var_type_id,
offset: 0,
size: 4,
}];
let datasec_type_id = btf.add_type(BtfType::new_datasec(name_offset, variables, 0));
let datasec_type_id =
btf.add_type(BtfType::DataSec(DataSec::new(name_offset, variables, 0)));
let features = Features {
btf_datasec: false,
@ -1077,11 +1085,11 @@ mod tests {
btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
.unwrap();
if let BtfType::Struct(fixed, members) = btf.type_by_id(datasec_type_id).unwrap() {
assert!(fixed.name_off == name_offset);
assert!(members.len() == 1);
assert!(members[0].type_ == var_type_id);
assert!(members[0].offset == 0)
if let BtfType::Struct(fixed) = btf.type_by_id(datasec_type_id).unwrap() {
assert!(fixed.name_offset == name_offset);
assert!(fixed.members.len() == 1);
assert!(fixed.members[0].btf_type == var_type_id);
assert!(fixed.members[0].offset == 0)
} else {
panic!("not a struct")
}
@ -1094,22 +1102,28 @@ mod tests {
fn test_fixup_datasec() {
let mut btf = Btf::new();
let name_offset = btf.add_string("int".to_string());
let int_type_id = btf.add_type(BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0));
let int_type_id = btf.add_type(BtfType::Int(Int::new(
name_offset,
4,
IntEncoding::Signed,
0,
)));
let name_offset = btf.add_string("foo".to_string());
let var_type_id = btf.add_type(BtfType::new_var(
let var_type_id = btf.add_type(BtfType::Var(Var::new(
name_offset,
int_type_id,
BTF_VAR_GLOBAL_EXTERN,
));
VarLinkage::Global,
)));
let name_offset = btf.add_string(".data/foo".to_string());
let variables = vec![btf_var_secinfo {
type_: var_type_id,
let variables = vec![DataSecEntry {
btf_type: var_type_id,
offset: 0,
size: 4,
}];
let datasec_type_id = btf.add_type(BtfType::new_datasec(name_offset, variables, 0));
let datasec_type_id =
btf.add_type(BtfType::DataSec(DataSec::new(name_offset, variables, 0)));
let features = Features {
btf_datasec: true,
@ -1123,17 +1137,17 @@ mod tests {
)
.unwrap();
if let BtfType::DataSec(fixed, sec_info) = btf.type_by_id(datasec_type_id).unwrap() {
assert!(fixed.name_off != name_offset);
assert!(unsafe { fixed.__bindgen_anon_1.size } == 32);
assert!(sec_info.len() == 1);
assert!(sec_info[0].type_ == var_type_id);
if let BtfType::DataSec(fixed) = btf.type_by_id(datasec_type_id).unwrap() {
assert!(fixed.name_offset != name_offset);
assert!(fixed.size == 32);
assert!(fixed.entries.len() == 1);
assert!(fixed.entries[0].btf_type == var_type_id);
assert!(
sec_info[0].offset == 64,
fixed.entries[0].offset == 64,
"expected 64, got {}",
sec_info[0].offset
fixed.entries[0].offset
);
assert!(btf.string_at(fixed.name_off).unwrap() == ".data.foo")
assert!(btf.string_at(fixed.name_offset).unwrap() == ".data.foo")
} else {
panic!("not a datasec")
}
@ -1146,25 +1160,31 @@ mod tests {
fn test_sanitize_func_and_proto() {
let mut btf = Btf::new();
let name_offset = btf.add_string("int".to_string());
let int_type_id = btf.add_type(BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0));
let int_type_id = btf.add_type(BtfType::Int(Int::new(
name_offset,
4,
IntEncoding::Signed,
0,
)));
let params = vec![
btf_param {
name_off: btf.add_string("a".to_string()),
type_: int_type_id,
BtfParam {
name_offset: btf.add_string("a".to_string()),
btf_type: int_type_id,
},
btf_param {
name_off: btf.add_string("b".to_string()),
type_: int_type_id,
BtfParam {
name_offset: btf.add_string("b".to_string()),
btf_type: int_type_id,
},
];
let func_proto_type_id = btf.add_type(BtfType::new_func_proto(params, int_type_id));
let func_proto_type_id =
btf.add_type(BtfType::FuncProto(FuncProto::new(params, int_type_id)));
let inc = btf.add_string("inc".to_string());
let func_type_id = btf.add_type(BtfType::new_func(
let func_type_id = btf.add_type(BtfType::Func(Func::new(
inc,
func_proto_type_id,
btf_func_linkage::BTF_FUNC_STATIC,
));
FuncLinkage::Static,
)));
let features = Features {
btf_func: false,
@ -1173,21 +1193,20 @@ mod tests {
btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
.unwrap();
if let BtfType::Enum(fixed, vars) = btf.type_by_id(func_proto_type_id).unwrap() {
assert!(fixed.name_off == 0);
assert!(vars.len() == 2);
assert!(btf.string_at(vars[0].name_off).unwrap() == "a");
assert!(vars[0].val == int_type_id as i32);
assert!(btf.string_at(vars[1].name_off).unwrap() == "b");
assert!(vars[1].val == int_type_id as i32);
if let BtfType::Enum(fixed) = btf.type_by_id(func_proto_type_id).unwrap() {
assert!(fixed.name_offset == 0);
assert!(fixed.variants.len() == 2);
assert!(btf.string_at(fixed.variants[0].name_offset).unwrap() == "a");
assert!(fixed.variants[0].value == int_type_id as i32);
assert!(btf.string_at(fixed.variants[1].name_offset).unwrap() == "b");
assert!(fixed.variants[1].value == int_type_id as i32);
} else {
panic!("not an emum")
}
if let BtfType::Typedef(fixed) = btf.type_by_id(func_type_id).unwrap() {
assert!(fixed.name_off == inc);
assert!(unsafe { fixed.__bindgen_anon_1.type_ } == func_proto_type_id);
assert!(fixed.name_offset == inc);
assert!(fixed.btf_type == func_proto_type_id);
} else {
panic!("not a typedef")
}
@ -1200,20 +1219,20 @@ mod tests {
fn test_fixup_func_proto() {
let mut btf = Btf::new();
let name_offset = btf.add_string("int".to_string());
let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0);
let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0));
let int_type_id = btf.add_type(int_type);
let params = vec![
btf_param {
name_off: 0,
type_: int_type_id,
BtfParam {
name_offset: 0,
btf_type: int_type_id,
},
btf_param {
name_off: 0,
type_: int_type_id,
BtfParam {
name_offset: 0,
btf_type: int_type_id,
},
];
let func_proto = BtfType::new_func_proto(params, int_type_id);
let func_proto = BtfType::FuncProto(FuncProto::new(params, int_type_id));
let func_proto_type_id = btf.add_type(func_proto);
let features = Features {
@ -1224,9 +1243,9 @@ mod tests {
btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
.unwrap();
if let BtfType::FuncProto(_, vars) = btf.type_by_id(func_proto_type_id).unwrap() {
assert!(btf.string_at(vars[0].name_off).unwrap() == "param0");
assert!(btf.string_at(vars[1].name_off).unwrap() == "param1");
if let BtfType::FuncProto(fixed) = btf.type_by_id(func_proto_type_id).unwrap() {
assert!(btf.string_at(fixed.params[0].name_offset).unwrap() == "param0");
assert!(btf.string_at(fixed.params[1].name_offset).unwrap() == "param1");
} else {
panic!("not a func_proto")
}
@ -1239,25 +1258,31 @@ mod tests {
fn test_sanitize_func_global() {
let mut btf = Btf::new();
let name_offset = btf.add_string("int".to_string());
let int_type_id = btf.add_type(BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0));
let int_type_id = btf.add_type(BtfType::Int(Int::new(
name_offset,
4,
IntEncoding::Signed,
0,
)));
let params = vec![
btf_param {
name_off: btf.add_string("a".to_string()),
type_: int_type_id,
BtfParam {
name_offset: btf.add_string("a".to_string()),
btf_type: int_type_id,
},
btf_param {
name_off: btf.add_string("b".to_string()),
type_: int_type_id,
BtfParam {
name_offset: btf.add_string("b".to_string()),
btf_type: int_type_id,
},
];
let func_proto_type_id = btf.add_type(BtfType::new_func_proto(params, int_type_id));
let func_proto_type_id =
btf.add_type(BtfType::FuncProto(FuncProto::new(params, int_type_id)));
let inc = btf.add_string("inc".to_string());
let func_type_id = btf.add_type(BtfType::new_func(
let func_type_id = btf.add_type(BtfType::Func(Func::new(
inc,
func_proto_type_id,
btf_func_linkage::BTF_FUNC_GLOBAL,
));
FuncLinkage::Global,
)));
let features = Features {
btf_func: true,
@ -1269,7 +1294,7 @@ mod tests {
.unwrap();
if let BtfType::Func(fixed) = btf.type_by_id(func_type_id).unwrap() {
assert!(type_vlen(fixed) == btf_func_linkage::BTF_FUNC_STATIC as usize);
assert!(fixed.linkage() == FuncLinkage::Static);
} else {
panic!("not a func")
}
@ -1282,7 +1307,7 @@ mod tests {
fn test_sanitize_float() {
let mut btf = Btf::new();
let name_offset = btf.add_string("float".to_string());
let float_type_id = btf.add_type(BtfType::new_float(name_offset, 16));
let float_type_id = btf.add_type(BtfType::Float(Float::new(name_offset, 16)));
let features = Features {
btf_float: false,
@ -1291,9 +1316,9 @@ mod tests {
btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
.unwrap();
if let BtfType::Struct(fixed, _) = btf.type_by_id(float_type_id).unwrap() {
assert!(fixed.name_off == 0);
assert!(unsafe { fixed.__bindgen_anon_1.size } == 16);
if let BtfType::Struct(fixed) = btf.type_by_id(float_type_id).unwrap() {
assert!(fixed.name_offset == 0);
assert!(fixed.size == 16);
} else {
panic!("not a struct")
}
@ -1306,13 +1331,23 @@ mod tests {
fn test_sanitize_decl_tag() {
let mut btf = Btf::new();
let name_offset = btf.add_string("int".to_string());
let int_type_id = btf.add_type(BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0));
let int_type_id = btf.add_type(BtfType::Int(Int::new(
name_offset,
4,
IntEncoding::Signed,
0,
)));
let name_offset = btf.add_string("foo".to_string());
let var_type_id = btf.add_type(BtfType::new_var(name_offset, int_type_id, BTF_VAR_STATIC));
let var_type_id = btf.add_type(BtfType::Var(Var::new(
name_offset,
int_type_id,
VarLinkage::Static,
)));
let name_offset = btf.add_string("decl_tag".to_string());
let decl_tag_type_id = btf.add_type(BtfType::new_decl_tag(name_offset, var_type_id, -1));
let decl_tag_type_id =
btf.add_type(BtfType::DeclTag(DeclTag::new(name_offset, var_type_id, -1)));
let features = Features {
btf_decl_tag: false,
@ -1321,9 +1356,9 @@ mod tests {
btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
.unwrap();
if let BtfType::Int(fixed, _) = btf.type_by_id(decl_tag_type_id).unwrap() {
assert!(fixed.name_off == name_offset);
assert!(unsafe { fixed.__bindgen_anon_1.size } == 1);
if let BtfType::Int(fixed) = btf.type_by_id(decl_tag_type_id).unwrap() {
assert!(fixed.name_offset == name_offset);
assert!(fixed.size == 1);
} else {
panic!("not an int")
}
@ -1336,11 +1371,11 @@ mod tests {
fn test_sanitize_type_tag() {
let mut btf = Btf::new();
let int_type_id = btf.add_type(BtfType::new_int(0, 4, BTF_INT_SIGNED, 0));
let int_type_id = btf.add_type(BtfType::Int(Int::new(0, 4, IntEncoding::Signed, 0)));
let name_offset = btf.add_string("int".to_string());
let type_tag_type = btf.add_type(BtfType::new_type_tag(name_offset, int_type_id));
btf.add_type(BtfType::new_ptr(0, type_tag_type));
let type_tag_type = btf.add_type(BtfType::TypeTag(TypeTag::new(name_offset, int_type_id)));
btf.add_type(BtfType::Ptr(Ptr::new(0, type_tag_type)));
let features = Features {
btf_type_tag: false,
@ -1350,7 +1385,7 @@ mod tests {
btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features)
.unwrap();
if let BtfType::Const(fixed) = btf.type_by_id(type_tag_type).unwrap() {
assert!(unsafe { fixed.__bindgen_anon_1.type_ } == int_type_id);
assert!(fixed.btf_type == int_type_id);
} else {
panic!("not a const")
}
@ -1358,4 +1393,29 @@ mod tests {
let raw = btf.to_bytes();
Btf::parse(&raw, Endianness::default()).unwrap();
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_read_btf_from_sys_fs() {
let btf = Btf::parse_file("/sys/kernel/btf/vmlinux", Endianness::default()).unwrap();
let task_struct_id = btf
.id_by_type_name_kind("task_struct", BtfKind::Struct)
.unwrap();
// we can't assert on exact ID since this may change across kernel versions
assert!(task_struct_id != 0);
let netif_id = btf
.id_by_type_name_kind("netif_receive_skb", BtfKind::Func)
.unwrap();
assert!(netif_id != 0);
let u32_def = btf.id_by_type_name_kind("__u32", BtfKind::Typedef).unwrap();
assert!(u32_def != 0);
let u32_base = btf.resolve_type(u32_def).unwrap();
assert!(u32_base != 0);
let u32_ty = btf.type_by_id(u32_base).unwrap();
assert_eq!(u32_ty.kind(), BtfKind::Int);
}
}

@ -9,8 +9,8 @@ use crate::{
},
obj::{
btf::{
fields_are_compatible, member_bit_field_size, member_bit_offset, types_are_compatible,
BtfType, MAX_SPEC_LEN,
fields_are_compatible, types_are_compatible, Array, BtfMember, BtfType, IntEncoding,
Struct, Union, MAX_SPEC_LEN,
},
Btf, BtfError, Object, Program, ProgramSection,
},
@ -207,7 +207,7 @@ fn relocate_btf_program<'target>(
}
let local_ty = local_btf.type_by_id(rel.type_id)?;
let local_name = &*local_btf.type_name(local_ty)?.unwrap();
let local_name = &*local_btf.type_name(local_ty)?;
let access_str = &*local_btf.string_at(rel.access_str_offset)?;
let local_spec = AccessSpec::new(local_btf, rel.type_id, access_str, *rel)?;
@ -288,10 +288,10 @@ fn find_candidates<'target>(
let mut candidates = Vec::new();
let local_name = flavorless_name(local_name);
for (type_id, ty) in target_btf.types().enumerate() {
if local_ty.kind()? != ty.kind()? {
if local_ty.kind() != ty.kind() {
continue;
}
let name = &*target_btf.type_name(ty)?.unwrap();
let name = &*target_btf.type_name(ty)?;
if local_name != flavorless_name(name) {
continue;
}
@ -342,9 +342,9 @@ fn match_candidate<'target>(
// the first accessor is guaranteed to have a name by construction
let local_variant_name = local_spec.accessors[0].name.as_ref().unwrap();
match target_ty {
BtfType::Enum(_, members) => {
for (index, member) in members.iter().enumerate() {
let target_variant_name = candidate.btf.string_at(member.name_off)?;
BtfType::Enum(en) => {
for (index, member) in en.variants.iter().enumerate() {
let target_variant_name = candidate.btf.string_at(member.name_offset)?;
if flavorless_name(local_variant_name)
== flavorless_name(&target_variant_name)
{
@ -389,24 +389,24 @@ fn match_candidate<'target>(
if i > 0 {
let target_ty = candidate.btf.type_by_id(target_id)?;
let array = match target_ty {
BtfType::Array(_, array) => array,
BtfType::Array(Array { array, .. }) => array,
_ => return Ok(None),
};
let var_len = array.nelems == 0 && {
let var_len = array.len == 0 && {
// an array is potentially variable length if it's the last field
// of the parent struct and has 0 elements
let parent = target_spec.accessors.last().unwrap();
let parent_ty = candidate.btf.type_by_id(parent.type_id)?;
match parent_ty {
BtfType::Struct(_, members) => parent.index == members.len() - 1,
BtfType::Struct(s) => parent.index == s.members.len() - 1,
_ => false,
}
};
if !var_len && accessor.index >= array.nelems as usize {
if !var_len && accessor.index >= array.len as usize {
return Ok(None);
}
target_id = candidate.btf.resolve_type(array.type_)?;
target_id = candidate.btf.resolve_type(array.element_type)?;
}
if target_spec.parts.len() == MAX_SPEC_LEN {
@ -442,21 +442,20 @@ fn match_member<'local, 'target>(
) -> Result<Option<u32>, ErrorWrapper> {
let local_ty = local_btf.type_by_id(local_accessor.type_id)?;
let local_member = match local_ty {
BtfType::Struct(_, members) | BtfType::Union(_, members) => {
// this won't panic, bounds are checked when local_spec is built in AccessSpec::new
members[local_accessor.index]
}
BtfType::Struct(s) => s.members.get(local_accessor.index).unwrap(),
BtfType::Union(u) => u.members.get(local_accessor.index).unwrap(),
_ => panic!("bug! this should only be called for structs and unions"),
};
let local_name = &*local_btf.string_at(local_member.name_off)?;
let local_name = &*local_btf.string_at(local_member.name_offset)?;
let target_id = target_btf.resolve_type(target_id)?;
let target_ty = target_btf.type_by_id(target_id)?;
let target_members = match target_ty {
BtfType::Struct(_, members) | BtfType::Union(_, members) => members,
let target_members: Vec<&BtfMember> = match target_ty.members() {
Some(members) => members.collect(),
// not a fields type, no match
_ => return Ok(None),
None => return Ok(None),
};
for (index, target_member) in target_members.iter().enumerate() {
@ -468,8 +467,9 @@ fn match_member<'local, 'target>(
.into());
}
let bit_offset = member_bit_offset(target_ty.info().unwrap(), target_member);
let target_name = &*target_btf.string_at(target_member.name_off)?;
// this will not panic as we've already established these are fields types
let bit_offset = target_ty.member_bit_offset(target_member).unwrap();
let target_name = &*target_btf.string_at(target_member.name_offset)?;
if target_name.is_empty() {
let ret = match_member(
@ -477,7 +477,7 @@ fn match_member<'local, 'target>(
local_spec,
local_accessor,
target_btf,
target_member.type_,
target_member.btf_type,
target_spec,
)?;
if ret.is_some() {
@ -488,9 +488,9 @@ fn match_member<'local, 'target>(
} else if local_name == target_name {
if fields_are_compatible(
local_spec.btf,
local_member.type_,
local_member.btf_type,
target_btf,
target_member.type_,
target_member.btf_type,
)? {
target_spec.bit_offset += bit_offset;
target_spec.parts.push(index);
@ -499,7 +499,7 @@ fn match_member<'local, 'target>(
index,
name: Some(target_name.to_owned()),
});
return Ok(Some(target_member.type_));
return Ok(Some(target_member.btf_type));
} else {
return Ok(None);
}
@ -558,7 +558,7 @@ impl<'a> AccessSpec<'a> {
}
}
RelocationKind::EnumVariantExists | RelocationKind::EnumVariantValue => match ty {
BtfType::Enum(_, members) => {
BtfType::Enum(en) => {
if parts.len() != 1 {
return Err(RelocationError::InvalidAccessString {
access_str: spec.to_string(),
@ -566,12 +566,12 @@ impl<'a> AccessSpec<'a> {
.into());
}
let index = parts[0];
if index >= members.len() {
if index >= en.variants.len() {
return Err(RelocationError::InvalidAccessIndex {
type_name: btf.err_type_name(ty),
spec: spec.to_string(),
index,
max_index: members.len(),
max_index: en.variants.len(),
error: "tried to access nonexistant enum variant".to_string(),
}
.into());
@ -579,7 +579,10 @@ impl<'a> AccessSpec<'a> {
let accessors = vec![Accessor {
type_id,
index,
name: Some(btf.string_at(members[index].name_off)?.to_string()),
name: Some(
btf.string_at(en.variants.get(index).unwrap().name_offset)?
.to_string(),
),
}];
AccessSpec {
@ -595,7 +598,7 @@ impl<'a> AccessSpec<'a> {
return Err(RelocationError::InvalidRelocationKindForType {
relocation_number: relocation.number,
relocation_kind: format!("{:?}", relocation.kind),
type_kind: format!("{:?}", ty.kind()?.unwrap()),
type_kind: format!("{:?}", ty.kind()),
error: "enum relocation on non-enum type".to_string(),
}
.into())
@ -618,9 +621,9 @@ impl<'a> AccessSpec<'a> {
type_id = btf.resolve_type(type_id)?;
let ty = btf.type_by_id(type_id)?;
use BtfType::*;
match ty {
Struct(t, members) | Union(t, members) => {
BtfType::Struct(Struct { members, .. })
| BtfType::Union(Union { members, .. }) => {
if index >= members.len() {
return Err(RelocationError::InvalidAccessIndex {
type_name: btf.err_type_name(ty),
@ -632,38 +635,38 @@ impl<'a> AccessSpec<'a> {
.into());
}
let member = members[index];
bit_offset += member_bit_offset(t.info, &member);
let member = &members[index];
bit_offset += ty.member_bit_offset(member).unwrap();
if member.name_off != 0 {
if member.name_offset != 0 {
accessors.push(Accessor {
type_id,
index,
name: Some(btf.string_at(member.name_off)?.to_string()),
name: Some(btf.string_at(member.name_offset)?.to_string()),
});
}
type_id = member.type_;
type_id = member.btf_type;
}
Array(_, array) => {
type_id = btf.resolve_type(array.type_)?;
let var_len = array.nelems == 0 && {
BtfType::Array(Array { array, .. }) => {
type_id = btf.resolve_type(array.element_type)?;
let var_len = array.len == 0 && {
// an array is potentially variable length if it's the last field
// of the parent struct and has 0 elements
let parent = accessors.last().unwrap();
let parent_ty = btf.type_by_id(parent.type_id)?;
match parent_ty {
Struct(_, members) => index == members.len() - 1,
BtfType::Struct(s) => index == s.members.len() - 1,
_ => false,
}
};
if !var_len && index >= array.nelems as usize {
if !var_len && index >= array.len as usize {
return Err(RelocationError::InvalidAccessIndex {
type_name: btf.err_type_name(ty),
spec: spec.to_string(),
index,
max_index: array.nelems as usize,
max_index: array.len as usize,
error: "array index out of bounds".to_string(),
}
.into());
@ -814,8 +817,8 @@ impl ComputedRelocation {
use BtfType::*;
match (local_ty, target_ty) {
(Ptr(_), Ptr(_)) => {}
(Int(_, local_info), Int(_, target_info))
if unsigned(*local_info) && unsigned(*target_info) => {}
(Int(local), Int(target))
if unsigned(local.data) && unsigned(target.data) => {}
_ => {
return Err(RelocationError::InvalidInstruction {
relocation_number: rel.number,
@ -885,7 +888,7 @@ impl ComputedRelocation {
let spec = spec.unwrap();
let accessor = &spec.accessors[0];
match spec.btf.type_by_id(accessor.type_id)? {
BtfType::Enum(_, variants) => variants[accessor.index].val as u32,
BtfType::Enum(en) => en.variants[accessor.index].value as u32,
_ => panic!("should not be reached"),
}
}
@ -946,9 +949,8 @@ impl ComputedRelocation {
let ty = spec.btf.type_by_id(accessor.type_id)?;
let (ll_ty, member) = match ty {
BtfType::Struct(ty, members) | BtfType::Union(ty, members) => {
(ty, members[accessor.index])
}
BtfType::Struct(t) => (ty, t.members.get(accessor.index).unwrap()),
BtfType::Union(t) => (ty, t.members.get(accessor.index).unwrap()),
_ => {
return Err(RelocationError::InvalidRelocationKindForType {
relocation_number: rel.number,
@ -961,17 +963,16 @@ impl ComputedRelocation {
};
let bit_off = spec.bit_offset as u32;
let member_type_id = spec.btf.resolve_type(member.type_)?;
let member_type_id = spec.btf.resolve_type(member.btf_type)?;
let member_ty = spec.btf.type_by_id(member_type_id)?;
let ll_member_ty = member_ty.btf_type().unwrap();
let mut byte_size;
let mut byte_off;
let mut bit_size = member_bit_field_size(ll_ty, &member) as u32;
let mut bit_size = ll_ty.member_bit_field_size(member).unwrap() as u32;
let is_bitfield = bit_size > 0;
if is_bitfield {
// find out the smallest int size to load the bitfield
byte_size = unsafe { ll_member_ty.__bindgen_anon_1.size };
byte_size = member_ty.size().unwrap();
byte_off = bit_off / 8 / byte_size * byte_size;
while bit_off + bit_size - byte_off * 8 > byte_size * 8 {
if byte_size >= 8 {
@ -1006,8 +1007,8 @@ impl ComputedRelocation {
value.value = byte_size;
}
FieldSigned => match member_ty {
BtfType::Enum(_, _) => value.value = 1,
BtfType::Int(_, i) => value.value = ((i >> 24) & 0x0F) & BTF_INT_SIGNED,
BtfType::Enum(_) => value.value = 1,
BtfType::Int(i) => value.value = i.encoding() as u32 & IntEncoding::Signed as u32,
_ => (),
},
#[cfg(target_endian = "little")]

File diff suppressed because it is too large Load Diff

@ -19,14 +19,14 @@ use relocation::*;
use crate::{
bpf_map_def,
generated::{bpf_insn, bpf_map_type::BPF_MAP_TYPE_ARRAY, btf_var_secinfo, BPF_F_RDONLY_PROG},
generated::{bpf_insn, bpf_map_type::BPF_MAP_TYPE_ARRAY, BPF_F_RDONLY_PROG},
obj::btf::{Btf, BtfError, BtfExt, BtfType},
programs::{CgroupSockAddrAttachType, CgroupSockAttachType, CgroupSockoptAttachType},
BpfError, BtfMapDef, PinningType,
};
use std::slice::from_raw_parts_mut;
use self::btf::{BtfKind, FuncSecInfo, LineSecInfo};
use self::btf::{Array, DataSecEntry, FuncSecInfo, LineSecInfo};
const KERNEL_VERSION_ANY: u32 = 0xFFFF_FFFE;
/// The first five __u32 of `bpf_map_def` must be defined.
@ -830,14 +830,14 @@ impl Object {
let btf = self.btf.as_ref().unwrap();
for t in btf.types() {
if let BtfType::DataSec(_, sec_info) = &t {
if let BtfType::DataSec(datasec) = &t {
let type_name = match btf.type_name(t) {
Ok(Some(name)) => name,
Ok(name) => name,
_ => continue,
};
if type_name == section.name {
// each btf_var_secinfo contains a map
for info in sec_info {
for info in &datasec.entries {
let (map_name, def) = parse_btf_map_def(btf, info)?;
let symbol_index = symbols
.get(&map_name)
@ -1144,20 +1144,20 @@ fn get_map_field(btf: &Btf, type_id: u32) -> Result<u32, BtfError> {
BtfType::Ptr(pty) => pty,
other => {
return Err(BtfError::UnexpectedBtfType {
type_id: other.kind()?.unwrap_or(BtfKind::Unknown) as u32,
type_id: other.btf_type().unwrap_or(0) as u32,
})
}
};
// Safety: union
let arr = match &btf.type_by_id(unsafe { pty.__bindgen_anon_1.type_ })? {
BtfType::Array(_, arr) => arr,
let arr = match &btf.type_by_id(pty.btf_type)? {
BtfType::Array(Array { array, .. }) => array,
other => {
return Err(BtfError::UnexpectedBtfType {
type_id: other.kind()?.unwrap_or(BtfKind::Unknown) as u32,
type_id: other.btf_type().unwrap_or(0) as u32,
})
}
};
Ok(arr.nelems)
Ok(arr.len)
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@ -1226,68 +1226,71 @@ fn parse_map_def(name: &str, data: &[u8]) -> Result<bpf_map_def, ParseError> {
}
}
fn parse_btf_map_def(btf: &Btf, info: &btf_var_secinfo) -> Result<(String, BtfMapDef), BtfError> {
let ty = match btf.type_by_id(info.type_)? {
BtfType::Var(ty, _) => ty,
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.kind()?.unwrap_or(BtfKind::Unknown) as u32,
type_id: other.btf_type().unwrap_or(0) as u32,
})
}
};
let map_name = btf.string_at(ty.name_off)?;
let map_name = btf.string_at(ty.name_offset)?;
let mut map_def = BtfMapDef::default();
// Safety: union
let root_type = btf.resolve_type(unsafe { ty.__bindgen_anon_1.type_ })?;
let members = match btf.type_by_id(root_type)? {
BtfType::Struct(_, members) => members,
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.kind()?.unwrap_or(BtfKind::Unknown) as u32,
type_id: other.btf_type().unwrap_or(0) as u32,
})
}
};
for m in members {
match btf.string_at(m.name_off)?.as_ref() {
for m in &s.members {
match btf.string_at(m.name_offset)?.as_ref() {
"type" => {
map_def.map_type = get_map_field(btf, m.type_)?;
map_def.map_type = get_map_field(btf, m.btf_type)?;
}
"key" => {
if let BtfType::Ptr(pty) = btf.type_by_id(m.type_)? {
if let BtfType::Ptr(pty) = btf.type_by_id(m.btf_type)? {
// Safety: union
let t = unsafe { pty.__bindgen_anon_1.type_ };
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.type_ });
return Err(BtfError::UnexpectedBtfType {
type_id: m.btf_type,
});
}
}
"key_size" => {
map_def.key_size = get_map_field(btf, m.type_)?;
map_def.key_size = get_map_field(btf, m.btf_type)?;
}
"value" => {
if let BtfType::Ptr(pty) = btf.type_by_id(m.type_)? {
// Safety: union
let t = unsafe { pty.__bindgen_anon_1.type_ };
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.type_ });
return Err(BtfError::UnexpectedBtfType {
type_id: m.btf_type,
});
}
}
"value_size" => {
map_def.value_size = get_map_field(btf, m.type_)?;
map_def.value_size = get_map_field(btf, m.btf_type)?;
}
"max_entries" => {
map_def.max_entries = get_map_field(btf, m.type_)?;
map_def.max_entries = get_map_field(btf, m.btf_type)?;
}
"map_flags" => {
map_def.map_flags = get_map_field(btf, m.type_)?;
map_def.map_flags = get_map_field(btf, m.btf_type)?;
}
"pinning" => {
let pinning = get_map_field(btf, m.type_)?;
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

@ -1,8 +1,12 @@
use crate::{
generated::{
btf_func_linkage, btf_param, btf_var_secinfo, BPF_F_REPLACE, BTF_INT_SIGNED, BTF_VAR_STATIC,
generated::BPF_F_REPLACE,
obj::{
btf::{
BtfParam, BtfType, DataSec, DataSecEntry, DeclTag, Float, Func, FuncLinkage, FuncProto,
Int, IntEncoding, Ptr, TypeTag, Var, VarLinkage,
},
copy_instructions,
},
obj::{btf::BtfType, copy_instructions},
Btf,
};
use libc::{c_char, c_long, close, ENOENT, ENOSPC};
@ -546,7 +550,7 @@ pub(crate) fn is_prog_name_supported() -> bool {
pub(crate) fn is_btf_supported() -> bool {
let mut btf = Btf::new();
let name_offset = btf.add_string("int".to_string());
let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0);
let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0));
btf.add_type(int_type);
let btf_bytes = btf.to_bytes();
@ -568,26 +572,26 @@ pub(crate) fn is_btf_supported() -> bool {
pub(crate) fn is_btf_func_supported() -> bool {
let mut btf = Btf::new();
let name_offset = btf.add_string("int".to_string());
let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0);
let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0));
let int_type_id = btf.add_type(int_type);
let a_name = btf.add_string("a".to_string());
let b_name = btf.add_string("b".to_string());
let params = vec![
btf_param {
name_off: a_name,
type_: int_type_id,
BtfParam {
name_offset: a_name,
btf_type: int_type_id,
},
btf_param {
name_off: b_name,
type_: int_type_id,
BtfParam {
name_offset: b_name,
btf_type: int_type_id,
},
];
let func_proto = BtfType::new_func_proto(params, int_type_id);
let func_proto = BtfType::FuncProto(FuncProto::new(params, int_type_id));
let func_proto_type_id = btf.add_type(func_proto);
let add = btf.add_string("inc".to_string());
let func = BtfType::new_func(add, func_proto_type_id, btf_func_linkage::BTF_FUNC_STATIC);
let func = BtfType::Func(Func::new(add, func_proto_type_id, FuncLinkage::Static));
btf.add_type(func);
let btf_bytes = btf.to_bytes();
@ -610,26 +614,26 @@ pub(crate) fn is_btf_func_supported() -> bool {
pub(crate) fn is_btf_func_global_supported() -> bool {
let mut btf = Btf::new();
let name_offset = btf.add_string("int".to_string());
let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0);
let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0));
let int_type_id = btf.add_type(int_type);
let a_name = btf.add_string("a".to_string());
let b_name = btf.add_string("b".to_string());
let params = vec![
btf_param {
name_off: a_name,
type_: int_type_id,
BtfParam {
name_offset: a_name,
btf_type: int_type_id,
},
btf_param {
name_off: b_name,
type_: int_type_id,
BtfParam {
name_offset: b_name,
btf_type: int_type_id,
},
];
let func_proto = BtfType::new_func_proto(params, int_type_id);
let func_proto = BtfType::FuncProto(FuncProto::new(params, int_type_id));
let func_proto_type_id = btf.add_type(func_proto);
let add = btf.add_string("inc".to_string());
let func = BtfType::new_func(add, func_proto_type_id, btf_func_linkage::BTF_FUNC_GLOBAL);
let func = BtfType::Func(Func::new(add, func_proto_type_id, FuncLinkage::Global));
btf.add_type(func);
let btf_bytes = btf.to_bytes();
@ -652,20 +656,20 @@ pub(crate) fn is_btf_func_global_supported() -> bool {
pub(crate) fn is_btf_datasec_supported() -> bool {
let mut btf = Btf::new();
let name_offset = btf.add_string("int".to_string());
let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0);
let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0));
let int_type_id = btf.add_type(int_type);
let name_offset = btf.add_string("foo".to_string());
let var_type = BtfType::new_var(name_offset, int_type_id, BTF_VAR_STATIC);
let var_type = BtfType::Var(Var::new(name_offset, int_type_id, VarLinkage::Static));
let var_type_id = btf.add_type(var_type);
let name_offset = btf.add_string(".data".to_string());
let variables = vec![btf_var_secinfo {
type_: var_type_id,
let variables = vec![DataSecEntry {
btf_type: var_type_id,
offset: 0,
size: 4,
}];
let datasec_type = BtfType::new_datasec(name_offset, variables, 4);
let datasec_type = BtfType::DataSec(DataSec::new(name_offset, variables, 4));
btf.add_type(datasec_type);
let btf_bytes = btf.to_bytes();
@ -688,7 +692,7 @@ pub(crate) fn is_btf_datasec_supported() -> bool {
pub(crate) fn is_btf_float_supported() -> bool {
let mut btf = Btf::new();
let name_offset = btf.add_string("float".to_string());
let float_type = BtfType::new_float(name_offset, 16);
let float_type = BtfType::Float(Float::new(name_offset, 16));
btf.add_type(float_type);
let btf_bytes = btf.to_bytes();
@ -711,15 +715,15 @@ pub(crate) fn is_btf_float_supported() -> bool {
pub(crate) fn is_btf_decl_tag_supported() -> bool {
let mut btf = Btf::new();
let name_offset = btf.add_string("int".to_string());
let int_type = BtfType::new_int(name_offset, 4, BTF_INT_SIGNED, 0);
let int_type = BtfType::Int(Int::new(name_offset, 4, IntEncoding::Signed, 0));
let int_type_id = btf.add_type(int_type);
let name_offset = btf.add_string("foo".to_string());
let var_type = BtfType::new_var(name_offset, int_type_id, BTF_VAR_STATIC);
let var_type = BtfType::Var(Var::new(name_offset, int_type_id, VarLinkage::Static));
let var_type_id = btf.add_type(var_type);
let name_offset = btf.add_string("decl_tag".to_string());
let decl_tag = BtfType::new_decl_tag(name_offset, var_type_id, -1);
let decl_tag = BtfType::DeclTag(DeclTag::new(name_offset, var_type_id, -1));
btf.add_type(decl_tag);
let btf_bytes = btf.to_bytes();
@ -742,14 +746,14 @@ pub(crate) fn is_btf_decl_tag_supported() -> bool {
pub(crate) fn is_btf_type_tag_supported() -> bool {
let mut btf = Btf::new();
let int_type = BtfType::new_int(0, 4, BTF_INT_SIGNED, 0);
let int_type = BtfType::Int(Int::new(0, 4, IntEncoding::Signed, 0));
let int_type_id = btf.add_type(int_type);
let name_offset = btf.add_string("int".to_string());
let type_tag = BtfType::new_type_tag(name_offset, int_type_id);
let type_tag = BtfType::TypeTag(TypeTag::new(name_offset, int_type_id));
let type_tag_type = btf.add_type(type_tag);
btf.add_type(BtfType::new_ptr(0, type_tag_type));
btf.add_type(BtfType::Ptr(Ptr::new(0, type_tag_type)));
let btf_bytes = btf.to_bytes();

Loading…
Cancel
Save