Skip to content

Commit 01a0eec

Browse files
aya: Support loading programs with ksyms
1 parent 3a3c451 commit 01a0eec

File tree

11 files changed

+1045
-4
lines changed

11 files changed

+1045
-4
lines changed

aya-obj/src/btf/btf.rs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

817952
impl Default for Btf {

0 commit comments

Comments
 (0)