Browse Source

aya-obj: Mutate BTF in-place without clone

The BTF we're working on is Cow anyway so modifying in-place is fine.
All we need to do is store some information before we start our
mutable iteration to avoid concurrently borrowing types both mutably and
immutably.

Signed-off-by: Dave Tucker <[email protected]>
Dave Tucker 1 year ago
parent
commit
098d436
1 changed files with 39 additions and 38 deletions
  1. 39 38
      aya-obj/src/btf/btf.rs

+ 39 - 38
aya-obj/src/btf/btf.rs

@@ -475,7 +475,7 @@ impl Btf {
     ) -> Result<(), BtfError> {
         let mut types = mem::take(&mut self.types);
         for i in 0..types.types.len() {
-            let t = &types.types[i];
+            let t = &mut types.types[i];
             let kind = t.kind();
             match t {
                 // Fixup PTR for Rust
@@ -483,9 +483,7 @@ impl Btf {
                 // While I figure out if this needs fixing in the Kernel or LLVM, we'll
                 // do a fixup here
                 BtfType::Ptr(ptr) => {
-                    let mut fixed_ty = ptr.clone();
-                    fixed_ty.name_offset = 0;
-                    types.types[i] = BtfType::Ptr(fixed_ty)
+                    ptr.name_offset = 0;
                 }
                 // Sanitize VAR if they are not supported
                 BtfType::Var(v) if !features.btf_datasec => {
@@ -496,7 +494,7 @@ impl Btf {
                     debug!("{}: not supported. replacing with STRUCT", kind);
 
                     // STRUCT aren't allowed to have "." in their name, fixup this if needed.
-                    let mut name_offset = t.name_offset();
+                    let mut name_offset = d.name_offset;
                     let name = self.string_at(name_offset)?;
 
                     // Handle any "." characters in struct names
@@ -506,18 +504,22 @@ impl Btf {
                         name_offset = self.add_string(&fixed_name);
                     }
 
-                    let mut members = vec![];
-                    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,
+                    let entries = std::mem::take(&mut d.entries);
+
+                    let members = entries
+                        .iter()
+                        .map(|e| {
+                            let mt = types.type_by_id(e.btf_type).unwrap();
+                            BtfMember {
+                                name_offset: mt.name_offset(),
+                                btf_type: e.btf_type,
+                                offset: e.offset * 8,
+                            }
                         })
-                    }
+                        .collect();
 
                     types.types[i] =
-                        BtfType::Struct(Struct::new(name_offset, members, d.entries.len() as u32));
+                        BtfType::Struct(Struct::new(name_offset, members, entries.len() as u32));
                 }
                 // Fixup DATASEC
                 // DATASEC sizes aren't always set by LLVM
@@ -527,18 +529,16 @@ impl Btf {
                     let name = self.string_at(d.name_offset)?;
                     let name = name.into_owned();
 
-                    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_offset = self.add_string(&fixed_name);
+                        d.name_offset = self.add_string(&fixed_name);
                     }
 
                     // There are some cases when the compiler does indeed populate the
                     // size
-                    if t.size().unwrap() > 0 {
+                    if d.size > 0 {
                         debug!("{} {}: size fixup not required", kind, name);
                     } else {
                         // We need to get the size of the section from the ELF file
@@ -551,22 +551,23 @@ impl Btf {
                             }
                         };
                         debug!("{} {}: fixup size to {}", kind, name, size);
-                        fixed_ty.size = *size as u32;
+                        d.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_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 mut entries = mem::take(&mut d.entries);
+                        let mut fixed_section = d.clone();
+
+                        for e in entries.iter_mut() {
+                            if let BtfType::Var(var) = types.type_by_id(e.btf_type)? {
                                 let var_name = self.string_at(var.name_offset)?;
                                 if var.linkage == VarLinkage::Static {
                                     debug!(
-                                        "{} {}: {} {}: fixup not required",
-                                        kind, name, var_kind, var_name
+                                        "{} {}: VAR {}: fixup not required",
+                                        kind, name, var_name
                                     );
                                     continue;
                                 }
@@ -579,27 +580,26 @@ impl Btf {
                                         });
                                     }
                                 };
-                                d.offset = *offset as u32;
+                                e.offset = *offset as u32;
                                 debug!(
-                                    "{} {}: {} {}: fixup offset {}",
-                                    kind, name, var_kind, var_name, offset
+                                    "{} {}: VAR {}: fixup offset {}",
+                                    kind, name, var_name, offset
                                 );
                             } else {
                                 return Err(BtfError::InvalidDatasec);
                             }
                         }
+                        fixed_section.entries = entries;
+                        types.types[i] = BtfType::DataSec(fixed_section);
                     }
-                    types.types[i] = BtfType::DataSec(fixed_ty);
                 }
                 // Fixup FUNC_PROTO
                 BtfType::FuncProto(ty) if features.btf_func => {
-                    let mut ty = ty.clone();
                     for (i, 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);
                 }
                 // Sanitize FUNC_PROTO
                 BtfType::FuncProto(ty) if !features.btf_func => {
@@ -635,7 +635,6 @@ impl Btf {
                         // and verified separately from their callers, while instead we
                         // want tracking info (eg bound checks) to be propagated to the
                         // memory builtins.
-                        let mut fixed_ty = ty.clone();
                         if ty.linkage() == FuncLinkage::Global {
                             if !features.btf_func_global {
                                 debug!(
@@ -645,9 +644,8 @@ impl Btf {
                             } else {
                                 debug!("changing FUNC {name} linkage to BTF_FUNC_STATIC");
                             }
-                            fixed_ty.set_linkage(FuncLinkage::Static);
+                            ty.set_linkage(FuncLinkage::Static);
                         }
-                        types.types[i] = BtfType::Func(fixed_ty);
                     }
                 }
                 // Sanitize FLOAT
@@ -1244,9 +1242,9 @@ mod tests {
             0,
         )));
 
-        let name_offset = btf.add_string("foo");
+        let var_name_offset = btf.add_string("foo");
         let var_type_id = btf.add_type(BtfType::Var(Var::new(
-            name_offset,
+            var_name_offset,
             int_type_id,
             VarLinkage::Static,
         )));
@@ -1271,11 +1269,14 @@ mod tests {
             assert_eq!(fixed.name_offset , name_offset);
             assert_matches!(*fixed.members, [
                 BtfMember {
-                    name_offset: _,
+                    name_offset: name_offset1,
                     btf_type,
                     offset: 0,
                 },
-            ] => assert_eq!(btf_type, var_type_id));
+            ] => {
+                assert_eq!(name_offset1, var_name_offset);
+                assert_eq!(btf_type, var_type_id);
+            })
         });
         // Ensure we can convert to bytes and back again
         let raw = btf.to_bytes();