@ -170,7 +170,7 @@ pub enum BtfError {
pub struct Btf {
pub struct Btf {
header : btf_header ,
header : btf_header ,
strings : Vec < u8 > ,
strings : Vec < u8 > ,
types : Vec < BtfType > ,
types : BtfTypes ,
_endianness : Endianness ,
_endianness : Endianness ,
}
}
@ -188,11 +188,15 @@ impl Btf {
str_len : 0x00 ,
str_len : 0x00 ,
} ,
} ,
strings : vec ! [ 0 ] ,
strings : vec ! [ 0 ] ,
types : vec! [ BtfType ::Unknown ] ,
types : BtfTypes::default ( ) ,
_endianness : Endianness ::default ( ) ,
_endianness : Endianness ::default ( ) ,
}
}
}
}
pub ( crate ) fn types ( & self ) -> impl Iterator < Item = & BtfType > {
self . types . types . iter ( )
}
pub ( crate ) fn add_string ( & mut self , name : String ) -> u32 {
pub ( crate ) fn add_string ( & mut self , name : String ) -> u32 {
let str = CString ::new ( name ) . unwrap ( ) ;
let str = CString ::new ( name ) . unwrap ( ) ;
let name_off = self . strings . len ( ) ;
let name_off = self . strings . len ( ) ;
@ -256,7 +260,7 @@ impl Btf {
header : & btf_header ,
header : & btf_header ,
data : & [ u8 ] ,
data : & [ u8 ] ,
endianness : Endianness ,
endianness : Endianness ,
) -> Result < Vec < BtfType > , BtfError > {
) -> Result < BtfTypes , BtfError > {
let hdr_len = header . hdr_len as usize ;
let hdr_len = header . hdr_len as usize ;
let type_off = header . type_off as usize ;
let type_off = header . type_off as usize ;
let type_len = header . type_len as usize ;
let type_len = header . type_len as usize ;
@ -266,7 +270,7 @@ impl Btf {
}
}
let mut data = & data [ base .. base + type_len ] ;
let mut data = & data [ base .. base + type_len ] ;
let mut types = vec! [ BtfType ::Unknown ] ;
let mut types = BtfTypes ::default ( ) ;
while ! data . is_empty ( ) {
while ! data . is_empty ( ) {
// Safety:
// Safety:
// read() reads POD values from ELF, which is sound, but the values can still contain
// read() reads POD values from ELF, which is sound, but the values can still contain
@ -305,34 +309,11 @@ impl Btf {
}
}
pub ( crate ) fn type_by_id ( & self , type_id : u32 ) -> Result < & BtfType , BtfError > {
pub ( crate ) fn type_by_id ( & self , type_id : u32 ) -> Result < & BtfType , BtfError > {
self . types
self . types . type_by_id ( type_id )
. get ( type_id as usize )
. ok_or ( BtfError ::UnknownBtfType { type_id } )
}
pub ( crate ) fn types ( & self ) -> impl Iterator < Item = & BtfType > {
self . types . iter ( )
}
}
pub ( crate ) fn resolve_type ( & self , root_type_id : u32 ) -> Result < u32 , BtfError > {
pub ( crate ) fn resolve_type ( & self , root_type_id : u32 ) -> Result < u32 , BtfError > {
let mut type_id = root_type_id ;
self . types . resolve_type ( root_type_id )
for _ in 0 .. MAX_RESOLVE_DEPTH {
let ty = self . type_by_id ( type_id ) ? ;
use BtfType ::* ;
match ty {
Volatile ( ty ) | Const ( ty ) | Restrict ( ty ) | Typedef ( ty ) | TypeTag ( ty ) = > {
// Safety: union
type_id = unsafe { ty . __bindgen_anon_1 . type_ } ;
continue ;
}
_ = > return Ok ( type_id ) ,
}
}
Err ( BtfError ::MaximumTypeDepthReached {
type_id : root_type_id ,
} )
}
}
pub ( crate ) fn type_name ( & self , ty : & BtfType ) -> Result < Option < Cow < ' _ , str > > , BtfError > {
pub ( crate ) fn type_name ( & self , ty : & BtfType ) -> Result < Option < Cow < ' _ , str > > , BtfError > {
@ -375,7 +356,7 @@ impl Btf {
let mut type_id = root_type_id ;
let mut type_id = root_type_id ;
let mut n_elems = 1 ;
let mut n_elems = 1 ;
for _ in 0 .. MAX_RESOLVE_DEPTH {
for _ in 0 .. MAX_RESOLVE_DEPTH {
let ty = self . type _by_id( type_id ) ? ;
let ty = self . type s. type _by_id( type_id ) ? ;
use BtfType ::* ;
use BtfType ::* ;
let size = match ty {
let size = match ty {
@ -422,143 +403,125 @@ impl Btf {
// Safety: btf_header is POD
// Safety: btf_header is POD
let mut buf = unsafe { bytes_of ::< btf_header > ( & self . header ) . to_vec ( ) } ;
let mut buf = unsafe { bytes_of ::< btf_header > ( & self . header ) . to_vec ( ) } ;
// Skip the first type since it's always BtfType::Unknown for type_by_id to work
// Skip the first type since it's always BtfType::Unknown for type_by_id to work
for t in self . types ( ) . skip ( 1 ) {
buf . extend ( self . types . to_bytes ( ) ) ;
let b = t . to_bytes ( ) ;
buf . put ( b . as_slice ( ) )
}
buf . put ( self . strings . as_slice ( ) ) ;
buf . put ( self . strings . as_slice ( ) ) ;
buf
buf
}
}
pub ( crate ) fn fixup (
pub ( crate ) fn fixup _and_sanitize (
& mut self ,
& mut self ,
section_sizes : & HashMap < String , u64 > ,
section_sizes : & HashMap < String , u64 > ,
symbol_offsets : & HashMap < String , u64 > ,
symbol_offsets : & HashMap < String , u64 > ,
features : & Features ,
) -> Result < ( ) , BtfError > {
) -> Result < ( ) , BtfError > {
let mut types = self . types . split_off ( 0 ) ;
let mut types = mem ::take ( & mut self . types ) ;
for t in & mut types {
for i in 0 .. types . types . len ( ) {
let kind = t . kind ( ) ? . unwrap_or_default ( ) ;
let kind = t ypes. types . get ( i ) . unwrap ( ) . kind ( ) ? . unwrap_or_default ( ) ;
// datasec sizes aren't set by llvm
// datasec sizes aren't set by llvm
// we need to fix them here before loading the btf to the kernel
// we need to fix them here before loading the btf to the kernel
match t {
match kind {
BtfType ::Ptr ( mut ty ) = > {
// Fixup PTR for Rust
// Rust emits names for pointer types, which the kernel doesn't like
// 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
// While I figure out if this needs fixing in the Kernel or LLVM, we'll
// do a fixup here
// do a fixup here
ty . name_off = 0 ;
BtfKind ::Ptr = > {
}
if let Some ( BtfType ::Ptr ( mut ty ) ) = types . types . get_mut ( i ) {
BtfType ::DataSec ( mut ty , data ) = > {
ty . name_off = 0 ;
// Start DataSec Fixups
let sec_name = self . string_at ( ty . name_off ) ? ;
let name = sec_name . to_string ( ) ;
// There are cases when the compiler does indeed populate the
// size. If we hit this case, push to the types vector and
// continue
if unsafe { ty . __bindgen_anon_1 . size > 0 } {
debug ! ( "{} {}: fixup not required" , kind , name ) ;
continue ;
}
}
}
// We need to get the size of the section from the ELF file
// Sanitize VAR if they are not supported
// Fortunately, we cached these when parsing it initially
BtfKind ::Var if ! features . btf_datasec = > {
// and we can this up by name in section_sizes
if let Some ( BtfType ::Var ( ty , _ ) ) = types . types . get ( i ) {
if let Some ( size ) = section_sizes . get ( & name ) {
types . types [ i ] = BtfType ::new_int ( ty . name_off , 1 , 0 , 0 ) ;
debug ! ( "{} {}: fixup size to {}" , kind , name , size ) ;
ty . __bindgen_anon_1 . size = * size as u32 ;
} else {
return Err ( BtfError ::UnknownSectionSize { section_name : name } ) ;
}
// 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 data {
let var_type = self . 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 {
debug ! (
"{} {}: {} {}: fixup not required" ,
kind , name , var_kind , var_name
) ;
continue ;
}
let offset = symbol_offsets . get ( & var_name ) . ok_or (
BtfError ::SymbolOffsetNotFound {
symbol_name : var_name . clone ( ) ,
} ,
) ? ;
d . offset = * offset as u32 ;
debug ! (
"{} {}: {} {}: fixup offset {}" ,
kind , name , var_kind , var_name , offset
) ;
} else {
return Err ( BtfError ::InvalidDatasec ) ;
}
}
}
}
}
BtfType ::FuncProto ( _ty , params ) = > {
// Sanitize DATASEC if they are not supported
for ( i , mut param ) in params . iter_mut ( ) . enumerate ( ) {
BtfKind ::DataSec if ! features . btf_datasec = > {
if param . name_off = = 0 & & param . type_ ! = 0 {
if let Some ( BtfType ::DataSec ( ty , data ) ) = types . types . get ( i ) {
param . name_off = self . add_string ( format! ( "param{}" , i ) ) ;
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_ ,
offset : member . offset * 8 ,
} )
}
}
let struct_type = BtfType ::new_struct ( ty . name_off , members , 0 ) ;
types . types [ i ] = struct_type ;
}
}
}
}
// The type does not need fixing up
// Fixup DATASEC
_ = > { }
BtfKind ::DataSec if features . btf_datasec = > {
}
if let Some ( BtfType ::DataSec ( ty , data ) ) = types . types . get_mut ( i ) {
}
// Start DataSec Fixups
self . types = types ;
let sec_name = self . string_at ( ty . name_off ) ? ;
Ok ( ( ) )
let name = sec_name . to_string ( ) ;
}
// There are some cases when the compiler does indeed populate the
// size
if unsafe { ty . __bindgen_anon_1 . size > 0 } {
debug ! ( "{} {}: fixup not required" , kind , name ) ;
continue ;
}
pub ( crate ) fn sanitize ( & self , features : & Features ) -> Result < Btf , BtfError > {
// We need to get the size of the section from the ELF file
let mut btf = Btf ::new ( ) ;
// Fortunately, we cached these when parsing it initially
// and we can this up by name in section_sizes
if let Some ( size ) = section_sizes . get ( & name ) {
debug ! ( "{} {}: fixup size to {}" , kind , name , size ) ;
ty . __bindgen_anon_1 . size = * size as u32 ;
} else {
return Err ( BtfError ::UnknownSectionSize { section_name : name } ) ;
}
btf . strings = self . strings . to_vec ( ) ;
// The Vec<btf_var_secinfo> contains BTF_KIND_VAR sections
btf . header . str_len = btf . strings . len ( ) as u32 ;
// 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 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 {
debug ! (
"{} {}: {} {}: fixup not required" ,
kind , name , var_kind , var_name
) ;
continue ;
}
// Skip the first type as it's only there
let offset = symbol_offsets . get ( & var_name ) . ok_or (
// to make type_by_id work
BtfError ::SymbolOffsetNotFound {
for t in & self . types [ 1 .. ] {
symbol_name : var_name . clone ( ) ,
let kind = t . kind ( ) ? . unwrap_or_default ( ) ;
} ,
match t {
) ? ;
BtfType ::Var ( ty , vars ) = > {
d . offset = * offset as u32 ;
if ! features . btf_datasec {
debug ! (
debug ! ( "{}: not supported. replacing with INT" , kind ) ;
"{} {}: {} {}: fixup offset {}" ,
let int_type = BtfType ::new_int ( ty . name_off , 1 , 0 , 0 ) ;
kind , name , var_kind , var_name , offset
btf . add_type ( int_type ) ;
) ;
} else {
} else {
btf . add_type ( BtfType ::Var ( * ty , * vars ) ) ;
return Err ( BtfError ::InvalidDatasec ) ;
}
}
}
}
}
}
BtfType ::DataSec ( ty , data ) = > {
// Fixup FUNC_PROTO
if ! features . btf_datasec {
BtfKind ::FuncProto if features . btf_func = > {
debug ! ( "{}: not supported. replacing with STRUCT" , kind ) ;
if let Some ( BtfType ::FuncProto ( _ , params ) ) = types . types . get_mut ( i ) {
let members : Vec < btf_member > = data
for ( i , mut param ) in params . iter_mut ( ) . enumerate ( ) {
. iter ( )
if param . name_off = = 0 & & param . type_ ! = 0 {
. map ( | p | -> btf_member {
param . name_off = self . add_string ( format! ( "param{}" , i ) ) ;
let mt = self . type_by_id ( p . type_ ) . unwrap ( ) ;
}
btf_member {
}
name_off : mt . btf_type ( ) . unwrap ( ) . name_off ,
type_ : p . type_ ,
offset : p . offset * 8 ,
}
} )
. collect ( ) ;
let struct_type = BtfType ::new_struct ( ty . name_off , members , 0 ) ;
btf . add_type ( struct_type ) ;
} else {
btf . add_type ( BtfType ::DataSec ( * ty , data . to_vec ( ) ) ) ;
}
}
}
}
BtfType ::FuncProto ( ty , vars ) = > {
// Sanitize FUNC_PROTO
if ! features . btf_func {
BtfKind ::FuncProto if features . btf_func = > {
if let Some ( BtfType ::FuncProto ( ty , vars ) ) = types . types . get ( i ) {
debug ! ( "{}: not supported. replacing with ENUM" , kind ) ;
debug ! ( "{}: not supported. replacing with ENUM" , kind ) ;
let members : Vec < btf_enum > = vars
let members : Vec < btf_enum > = vars
. iter ( )
. iter ( )
@ -570,66 +533,62 @@ impl Btf {
} )
} )
. collect ( ) ;
. collect ( ) ;
let enum_type = BtfType ::new_enum ( ty . name_off , members ) ;
let enum_type = BtfType ::new_enum ( ty . name_off , members ) ;
btf . add_type ( enum_type ) ;
types . types [ i ] = enum_type ;
} else {
btf . add_type ( BtfType ::FuncProto ( * ty , vars . to_vec ( ) ) ) ;
}
}
}
}
BtfType ::Func ( mut ty ) = > {
// Sanitize FUNC
if ! features . btf_func {
BtfKind ::Func if ! features . btf_func = > {
if let Some ( BtfType ::Func ( ty ) ) = types . types . get ( i ) {
debug ! ( "{}: not supported. replacing with TYPEDEF" , kind ) ;
debug ! ( "{}: not supported. replacing with TYPEDEF" , kind ) ;
let typedef_type =
let typedef_type =
BtfType ::new_typedef ( ty . name_off , unsafe { ty . __bindgen_anon_1 . type_ } ) ;
BtfType ::new_typedef ( ty . name_off , unsafe { ty . __bindgen_anon_1 . type_ } ) ;
btf . add_type ( typedef_type ) ;
types . types [ i ] = typedef_type ;
} else if type_vlen ( & ty ) = = btf_func_linkage ::BTF_FUNC_GLOBAL as usize
& & ! features . btf_func_global
{
debug ! (
"{}: BTF_FUNC_GLOBAL not supported. replacing with BTF_FUNC_STATIC" ,
kind
) ;
ty . info = ( ty . info & 0xFFFF0000 )
| ( btf_func_linkage ::BTF_FUNC_STATIC as u32 ) & 0xFFFF ;
btf . add_type ( BtfType ::Func ( ty ) ) ;
} else {
btf . add_type ( BtfType ::Func ( ty ) ) ;
}
}
}
}
BtfType ::Float ( ty ) = > {
// Sanitize BTF_FUNC_GLOBAL
if ! features . btf_float {
BtfKind ::Func if ! features . btf_func_global = > {
if let Some ( BtfType ::Func ( ty ) ) = types . types . get_mut ( i ) {
if type_vlen ( ty ) = = btf_func_linkage ::BTF_FUNC_GLOBAL as usize {
debug ! (
"{}: BTF_FUNC_GLOBAL not supported. replacing with BTF_FUNC_STATIC" ,
kind
) ;
ty . info = ( ty . info & 0xFFFF0000 )
| ( btf_func_linkage ::BTF_FUNC_STATIC as u32 ) & 0xFFFF ;
}
}
}
// Sanitize FLOAT
BtfKind ::Float if ! features . btf_float = > {
if let Some ( BtfType ::Float ( ty ) ) = types . types . get ( i ) {
debug ! ( "{}: not supported. replacing with STRUCT" , kind ) ;
debug ! ( "{}: not supported. replacing with STRUCT" , kind ) ;
let struct_ty =
let struct_ty =
BtfType ::new_struct ( 0 , vec! [ ] , unsafe { ty . __bindgen_anon_1 . size } ) ;
BtfType ::new_struct ( 0 , vec! [ ] , unsafe { ty . __bindgen_anon_1 . size } ) ;
btf . add_type ( struct_ty ) ;
types . types [ i ] = struct_ty ;
} else {
btf . add_type ( BtfType ::Float ( * ty ) ) ;
}
}
}
}
BtfType ::DeclTag ( ty , btf_decl_tag ) = > {
// Sanitize DECL_TAG
if ! features . btf_decl_tag {
BtfKind ::DeclTag if ! features . btf_decl_tag = > {
if let Some ( BtfType ::DeclTag ( ty , _ ) ) = types . types . get ( i ) {
debug ! ( "{}: not supported. replacing with INT" , kind ) ;
debug ! ( "{}: not supported. replacing with INT" , kind ) ;
let int_type = BtfType ::new_int ( ty . name_off , 1 , 0 , 0 ) ;
let int_type = BtfType ::new_int ( ty . name_off , 1 , 0 , 0 ) ;
btf . add_type ( int_type ) ;
types . types [ i ] = int_type ;
} else {
btf . add_type ( BtfType ::DeclTag ( * ty , * btf_decl_tag ) ) ;
}
}
}
}
BtfType ::TypeTag ( ty ) = > {
// Sanitize TYPE_TAG
if ! features . btf_type_tag {
BtfKind ::TypeTag if ! features . btf_type_tag = > {
if let Some ( BtfType ::TypeTag ( ty ) ) = types . types . get ( i ) {
debug ! ( "{}: not supported. replacing with CONST" , kind ) ;
debug ! ( "{}: not supported. replacing with CONST" , kind ) ;
let const_type = BtfType ::new_const ( unsafe { ty . __bindgen_anon_1 . type_ } ) ;
let const_type = BtfType ::new_const ( unsafe { ty . __bindgen_anon_1 . type_ } ) ;
btf . add_type ( const_type ) ;
types . types [ i ] = const_type ;
} else {
btf . add_type ( BtfType ::TypeTag ( * ty ) ) ;
}
}
}
}
// The type does not need sanitizing
// The type does not need fixing up or sanitization
ty = > {
_ = > { }
btf . add_type ( ty . clone ( ) ) ;
}
}
}
}
}
Ok ( btf )
self . types = types ;
Ok ( ( ) )
}
}
}
}
@ -857,6 +816,67 @@ impl<'a> Iterator for SecInfoIter<'a> {
}
}
}
}
/// BtfTypes allows for access and manipulation of a
/// collection of BtfType objects
#[ derive(Debug, Clone) ]
pub ( crate ) struct BtfTypes {
pub ( crate ) types : Vec < BtfType > ,
}
impl Default for BtfTypes {
fn default ( ) -> Self {
Self {
types : vec ! [ BtfType ::Unknown ] ,
}
}
}
impl BtfTypes {
pub ( crate ) fn to_bytes ( & self ) -> Vec < u8 > {
let mut buf = vec! [ ] ;
for t in self . types . iter ( ) . skip ( 1 ) {
let b = t . to_bytes ( ) ;
buf . put ( b . as_slice ( ) )
}
buf
}
pub ( crate ) fn len ( & self ) -> usize {
self . types . len ( )
}
pub ( crate ) fn push ( & mut self , value : BtfType ) {
self . types . push ( value )
}
pub ( crate ) fn type_by_id ( & self , type_id : u32 ) -> Result < & BtfType , BtfError > {
self . types
. get ( type_id as usize )
. ok_or ( BtfError ::UnknownBtfType { type_id } )
}
pub ( crate ) fn resolve_type ( & self , root_type_id : u32 ) -> Result < u32 , BtfError > {
let mut type_id = root_type_id ;
for _ in 0 .. MAX_RESOLVE_DEPTH {
let ty = self . type_by_id ( type_id ) ? ;
use BtfType ::* ;
match ty {
Volatile ( ty ) | Const ( ty ) | Restrict ( ty ) | Typedef ( ty ) | TypeTag ( ty ) = > {
// Safety: union
type_id = unsafe { ty . __bindgen_anon_1 . type_ } ;
continue ;
}
_ = > return Ok ( type_id ) ,
}
}
Err ( BtfError ::MaximumTypeDepthReached {
type_id : root_type_id ,
} )
}
}
#[ derive(Debug) ]
#[ derive(Debug) ]
pub ( crate ) struct SecInfo < ' a > {
pub ( crate ) struct SecInfo < ' a > {
sec_name_off : u32 ,
sec_name_off : u32 ,
@ -1045,14 +1065,6 @@ mod tests {
let func = BtfType ::new_func ( add , func_proto_type_id , btf_func_linkage ::BTF_FUNC_GLOBAL ) ;
let func = BtfType ::new_func ( add , func_proto_type_id , btf_func_linkage ::BTF_FUNC_GLOBAL ) ;
btf . add_type ( func ) ;
btf . add_type ( func ) ;
let name_offset = btf . add_string ( "int" . to_string ( ) ) ;
let type_tag = BtfType ::new_type_tag ( name_offset , int_type_id ) ;
btf . add_type ( type_tag ) ;
let name_offset = btf . add_string ( "decl_tag" . to_string ( ) ) ;
let decl_tag = BtfType ::new_decl_tag ( name_offset , var_type_id , - 1 ) ;
btf . add_type ( decl_tag ) ;
let cases = HashMap ::from ( [
let cases = HashMap ::from ( [
(
(
"noop" ,
"noop" ,
@ -1162,8 +1174,9 @@ mod tests {
for ( name , features ) in cases {
for ( name , features ) in cases {
println! ( "[CASE] Sanitize {}" , name ) ;
println! ( "[CASE] Sanitize {}" , name ) ;
let new_btf = btf . sanitize ( & features ) . unwrap ( ) ;
btf . fixup_and_sanitize ( & HashMap ::new ( ) , & HashMap ::new ( ) , & features )
let raw_new_btf = new_btf . to_bytes ( ) ;
. unwrap ( ) ;
let raw_new_btf = btf . to_bytes ( ) ;
Btf ::parse ( & raw_new_btf , Endianness ::default ( ) ) . unwrap ( ) ;
Btf ::parse ( & raw_new_btf , Endianness ::default ( ) ) . unwrap ( ) ;
}
}
}
}