@ -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_off set = 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_off set 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_off set = 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 d ata {
let mt = types . type_by_id ( member . type_ ) . unwrap ( ) ;
members . push ( btf_m ember {
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 ( BtfM ember {
name_off set : 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_off set = 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 ( v ty, v ar) = var_type {
let var_name = self . string_at ( v ty. 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 ( v ar) = var_type {
let var_name = self . string_at ( v ar. 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_off set = = 0 & & param . btf_ type ! = 0 {
param . name_off set = 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_e num {
name_off : p . name_off ,
val : p . type_ as i32 ,
. map ( | p | BtfE num {
name_off set : p . name_off set ,
val ue : 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 ty pe_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_off set = = 0 ,
"expected offset 0, got {}" ,
fixed . name_off
fixed . name_off set
)
} 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_off set = = 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_off set = = 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_off set ! = 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_off set ) . 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 ,
BtfP aram {
name_off set : btf . add_string ( "a" . to_string ( ) ) ,
btf_ type: int_type_id ,
} ,
btf_p aram {
name_off : btf . add_string ( "b" . to_string ( ) ) ,
type_ : int_type_id ,
BtfP aram {
name_off set : 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_off set = = 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_p aram {
name_off : 0 ,
type_ : int_type_id ,
BtfP aram {
name_off set : 0 ,
btf_ type: int_type_id ,
} ,
btf_p aram {
name_off : 0 ,
type_ : int_type_id ,
BtfP aram {
name_off set : 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 ( var s[ 0 ] . name_off ) . unwrap ( ) = = "param0" ) ;
assert! ( btf . string_at ( var s[ 1 ] . name_off ) . unwrap ( ) = = "param1" ) ;
if let BtfType ::FuncProto ( fixed ) = btf . type_by_id ( func_proto_type_id ) . unwrap ( ) {
assert! ( btf . string_at ( fixed. param s[ 0 ] . name_off set ) . unwrap ( ) = = "param0" ) ;
assert! ( btf . string_at ( fixed. param s[ 1 ] . name_off set ) . 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 ,
BtfP aram {
name_off set : btf . add_string ( "a" . to_string ( ) ) ,
btf_ type: int_type_id ,
} ,
btf_p aram {
name_off : btf . add_string ( "b" . to_string ( ) ) ,
type_ : int_type_id ,
BtfP aram {
name_off set : 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_off set = = 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_off set = = 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 ) ;
}
}