@@ -812,6 +812,141 @@ impl Btf {
812812 self . types = types;
813813 Ok ( ( ) )
814814 }
815+
816+ /// Fixes up BTF for `.ksyms` datasec entries containing extern kernel symbol and
817+ /// makes it acceptable by the kernel:
818+ ///
819+ /// * Changes linkage of extern functions to `GLOBAL`, fixes parameter names, injects
820+ /// a dummy variable representing them in datasec.
821+ /// * Changes linkage of extern variables to `GLOBAL_ALLOCATED`, replaces their type
822+ /// with `int`.
823+ pub ( crate ) fn fixup_ksyms_datasec (
824+ & mut self ,
825+ datasec_id : u32 ,
826+ dummy_var_id : Option < u32 > ,
827+ ) -> Result < ( ) , BtfError > {
828+ // Extract dummy variable's name offset and type ID for patching func_proto names and datasec entries.
829+ // If dummy var exists: use its name_offset (for string table patching) and btf_type (underlying int type).
830+ // If no dummy var (fallback): search for a 4-byte int type directly, with no name_offset.
831+ // Both paths provide an int_btf_id to ensure type consistency in datasec variable entries.
832+ let ( dummy_var_name_offset, int_btf_id) = if let Some ( dummy_id) = dummy_var_id {
833+ let dummy_type = & self . types . types [ dummy_id as usize ] ;
834+ if let BtfType :: Var ( v) = dummy_type {
835+ ( Some ( v. name_offset ) , v. btf_type )
836+ } else {
837+ return Err ( BtfError :: InvalidDatasec ) ;
838+ }
839+ } else {
840+ let int_id = self
841+ . types
842+ . types
843+ . iter ( )
844+ . enumerate ( )
845+ . find_map ( |( idx, t) | {
846+ if let BtfType :: Int ( int_type) = t {
847+ ( int_type. size == 4 ) . then_some ( idx as u32 )
848+ } else {
849+ None
850+ }
851+ } )
852+ . ok_or ( BtfError :: InvalidDatasec ) ?;
853+
854+ ( None , int_id)
855+ } ;
856+
857+ let datasec_name = {
858+ let datasec = & self . types . types [ datasec_id as usize ] ;
859+ let BtfType :: DataSec ( d) = datasec else {
860+ return Err ( BtfError :: InvalidDatasec ) ;
861+ } ;
862+ self . string_at ( d. name_offset ) ?. into_owned ( )
863+ } ;
864+
865+ debug ! ( "DATASEC {datasec_name}: fixing up extern ksyms" ) ;
866+
867+ let entry_type_ids: Vec < u32 > = {
868+ let BtfType :: DataSec ( d) = & self . types . types [ datasec_id as usize ] else {
869+ return Err ( BtfError :: InvalidDatasec ) ;
870+ } ;
871+ d. entries . iter ( ) . map ( |e| e. btf_type ) . collect ( )
872+ } ;
873+
874+ let mut offset = 0u32 ;
875+ let size = mem:: size_of :: < i32 > ( ) as u32 ;
876+
877+ for ( i, & type_id) in entry_type_ids. iter ( ) . enumerate ( ) {
878+ let type_kind = match & self . types . types [ type_id as usize ] {
879+ BtfType :: Func ( _) => "func" ,
880+ BtfType :: Var ( _) => "var" ,
881+ _ => return Err ( BtfError :: InvalidDatasec ) ,
882+ } ;
883+
884+ match type_kind {
885+ "func" => {
886+ let ( func_name, proto_id) = {
887+ let BtfType :: Func ( f) = & self . types . types [ type_id as usize ] else {
888+ return Err ( BtfError :: InvalidDatasec ) ;
889+ } ;
890+ ( self . string_at ( f. name_offset ) ?. into_owned ( ) , f. btf_type )
891+ } ;
892+
893+ if let BtfType :: Func ( f) = & mut self . types . types [ type_id as usize ] {
894+ f. set_linkage ( FuncLinkage :: Global ) ;
895+ }
896+
897+ if let Some ( dummy_name_off) = dummy_var_name_offset {
898+ if let BtfType :: FuncProto ( func_proto) =
899+ & mut self . types . types [ proto_id as usize ]
900+ {
901+ for param in & mut func_proto. params {
902+ if param. btf_type != 0 && param. name_offset == 0 {
903+ param. name_offset = dummy_name_off;
904+ }
905+ }
906+ }
907+ }
908+
909+ if let ( Some ( dummy_id) , BtfType :: DataSec ( d) ) =
910+ ( dummy_var_id, & mut self . types . types [ datasec_id as usize ] )
911+ {
912+ d. entries [ i] . btf_type = dummy_id;
913+ }
914+
915+ debug ! ( "DATASEC {datasec_name}: FUNC {func_name}: fixup offset {offset}" ) ;
916+ }
917+ "var" => {
918+ let var_name = {
919+ let BtfType :: Var ( v) = & self . types . types [ type_id as usize ] else {
920+ return Err ( BtfError :: InvalidDatasec ) ;
921+ } ;
922+ self . string_at ( v. name_offset ) ?. into_owned ( )
923+ } ;
924+
925+ if let BtfType :: Var ( v) = & mut self . types . types [ type_id as usize ] {
926+ v. linkage = VarLinkage :: Global ;
927+ v. btf_type = int_btf_id;
928+ }
929+
930+ debug ! ( "DATASEC {datasec_name}: VAR {var_name}: fixup offset {offset}" ) ;
931+ }
932+ _ => unreachable ! ( ) ,
933+ }
934+
935+ if let BtfType :: DataSec ( d) = & mut self . types . types [ datasec_id as usize ] {
936+ d. entries [ i] . offset = offset;
937+ d. entries [ i] . size = size;
938+ }
939+
940+ offset += size;
941+ }
942+
943+ if let BtfType :: DataSec ( d) = & mut self . types . types [ datasec_id as usize ] {
944+ d. size = offset;
945+ debug ! ( "DATASEC {datasec_name}: fixup size to {offset}" ) ;
946+ }
947+
948+ Ok ( ( ) )
949+ }
815950}
816951
817952impl Default for Btf {
0 commit comments