|
|
|
@ -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,35 +316,23 @@ 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 {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
None => continue,
|
|
|
|
|
if ty.kind() != kind {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
match self.type_name(ty)? {
|
|
|
|
|
Some(ty_name) => {
|
|
|
|
|
if ty_name == name {
|
|
|
|
|
return Ok(type_id as u32);
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
None => continue,
|
|
|
|
|
if self.type_name(ty)? == name {
|
|
|
|
|
return Ok(type_id as u32);
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Err(BtfError::UnknownBtfTypeName {
|
|
|
|
@ -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_;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
Unknown | Fwd(_) | Func(_) | FuncProto(_, _) => {
|
|
|
|
|
return Err(BtfError::UnexpectedBtfType { type_id })
|
|
|
|
|
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 });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|