浏览代码

obj: Add Btf::to_bytes

This allows for parsed BTF to be re-encoded such that it could be loaded
in to the kernel. It moves bytes_of to the utils package. We could use
Object::bytes_of, but this requires the impl of the Pod trait on
generated code.

Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
Dave Tucker 3 年之前
父节点
当前提交
379bb313b1
共有 2 个文件被更改,包括 192 次插入17 次删除
  1. 66 0
      aya/src/obj/btf/btf.rs
  2. 126 17
      aya/src/obj/btf/types.rs

+ 66 - 0
aya/src/obj/btf/btf.rs

@@ -7,12 +7,15 @@ use std::{
     ptr,
 };
 
+use bytes::BufMut;
+
 use object::Endianness;
 use thiserror::Error;
 
 use crate::{
     generated::{btf_ext_header, btf_header},
     obj::btf::{relocation::Relocation, BtfKind, BtfType},
+    util::bytes_of,
 };
 
 pub(crate) const MAX_RESOLVE_DEPTH: u8 = 32;
@@ -291,6 +294,17 @@ impl Btf {
             type_id: root_type_id,
         })
     }
+
+    pub(crate) fn to_bytes(&self) -> Vec<u8> {
+        // Safety: btf_header is POD
+        let mut buf = unsafe { bytes_of::<btf_header>(&self.header).to_vec() };
+        for t in self.types() {
+            let b = t.to_bytes();
+            buf.put(b.as_slice())
+        }
+        buf.put(self.strings.as_slice());
+        buf
+    }
 }
 
 unsafe fn read_btf_header(data: &[u8]) -> btf_header {
@@ -472,4 +486,56 @@ mod tests {
         assert_eq!(header.str_off, 0x2a5464);
         assert_eq!(header.str_len, 0x1c6410);
     }
+
+    #[test]
+    fn test_parse_btf() {
+        // this generated BTF data is from an XDP program that simply returns XDP_PASS
+        // compiled using clang
+        let data: &[u8] = &[
+            0x9f, 0xeb, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x01,
+            0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00,
+            0x00, 0x04, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00,
+            0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+            0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00,
+            0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
+            0x03, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+            0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+            0x00, 0x0d, 0x06, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+            0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00,
+            0x00, 0x01, 0x69, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0c, 0x05, 0x00, 0x00, 0x00,
+            0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00,
+            0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+            0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xbc, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+            0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00,
+            0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
+            0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x78,
+            0x64, 0x70, 0x5f, 0x6d, 0x64, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x64, 0x61, 0x74,
+            0x61, 0x5f, 0x65, 0x6e, 0x64, 0x00, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6d, 0x65, 0x74,
+            0x61, 0x00, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x69, 0x66, 0x69, 0x6e,
+            0x64, 0x65, 0x78, 0x00, 0x72, 0x78, 0x5f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x69,
+            0x6e, 0x64, 0x65, 0x78, 0x00, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x69, 0x66,
+            0x69, 0x6e, 0x64, 0x65, 0x78, 0x00, 0x5f, 0x5f, 0x75, 0x33, 0x32, 0x00, 0x75, 0x6e,
+            0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x00, 0x63, 0x74, 0x78,
+            0x00, 0x69, 0x6e, 0x74, 0x00, 0x78, 0x64, 0x70, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x00,
+            0x78, 0x64, 0x70, 0x2f, 0x70, 0x61, 0x73, 0x73, 0x00, 0x2f, 0x68, 0x6f, 0x6d, 0x65,
+            0x2f, 0x64, 0x61, 0x76, 0x65, 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x62, 0x70, 0x66, 0x64,
+            0x2f, 0x62, 0x70, 0x66, 0x2f, 0x78, 0x64, 0x70, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x2e,
+            0x62, 0x70, 0x66, 0x2e, 0x63, 0x00, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
+            0x72, 0x6e, 0x20, 0x58, 0x44, 0x50, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x3b, 0x00, 0x63,
+            0x68, 0x61, 0x72, 0x00, 0x5f, 0x5f, 0x41, 0x52, 0x52, 0x41, 0x59, 0x5f, 0x53, 0x49,
+            0x5a, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x5f, 0x00, 0x5f, 0x6c, 0x69, 0x63,
+            0x65, 0x6e, 0x73, 0x65, 0x00, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x00,
+        ];
+        let got = Btf::parse(data, Endianness::default());
+        match got {
+            Ok(_) => {}
+            Err(e) => panic!("{}", e),
+        }
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2);
+    }
 }

+ 126 - 17
aya/src/obj/btf/types.rs

@@ -149,6 +149,67 @@ impl BtfType {
         })
     }
 
+    pub(crate) fn to_bytes(&self) -> Vec<u8> {
+        fn bytes_of<T>(val: &T) -> &[u8] {
+            // Safety: all btf types are POD
+            unsafe { crate::util::bytes_of(val) }
+        }
+        match self {
+            BtfType::Fwd(btf_type)
+            | BtfType::Const(btf_type)
+            | BtfType::Volatile(btf_type)
+            | BtfType::Restrict(btf_type)
+            | BtfType::Ptr(btf_type)
+            | BtfType::Typedef(btf_type)
+            | BtfType::Func(btf_type)
+            | BtfType::Float(btf_type) => bytes_of::<btf_type>(btf_type).to_vec(),
+            BtfType::Int(btf_type, len) => {
+                let mut buf = bytes_of::<btf_type>(btf_type).to_vec();
+                buf.append(&mut len.to_ne_bytes().to_vec());
+                buf
+            }
+            BtfType::Enum(btf_type, enums) => {
+                let mut buf = bytes_of::<btf_type>(btf_type).to_vec();
+                for en in enums { 
+                    buf.append(&mut bytes_of::<btf_enum>(en).to_vec());
+                }
+                buf
+            }
+            BtfType::Array(btf_type, btf_array) => {
+                let mut buf = bytes_of::<btf_type>(btf_type).to_vec();
+                buf.append(&mut bytes_of::<btf_array>(btf_array).to_vec());
+                buf
+            }
+            BtfType::Struct(btf_type, btf_members) | BtfType::Union(btf_type, btf_members) => {
+                let mut buf = bytes_of::<btf_type>(btf_type).to_vec();
+                for m in btf_members {
+                    buf.append(&mut bytes_of::<btf_member>(m).to_vec());
+                }
+                buf
+            }
+            BtfType::FuncProto(btf_type, btf_params) => {
+                let mut buf = bytes_of::<btf_type>(btf_type).to_vec();
+                for p in btf_params {
+                    buf.append(&mut bytes_of::<btf_param>(p).to_vec());
+                }
+                buf
+            }
+            BtfType::Var(btf_type, btf_var) => {
+                let mut buf = bytes_of::<btf_type>(btf_type).to_vec();
+                buf.append(&mut bytes_of::<btf_var>(btf_var).to_vec());
+                buf
+            }
+            BtfType::DataSec(btf_type, btf_var_secinfo) => {
+                let mut buf = bytes_of::<btf_type>(btf_type).to_vec();
+                for s in btf_var_secinfo {
+                    buf.append(&mut bytes_of::<btf_var_secinfo>(s).to_vec());
+                }
+                buf
+            }
+            BtfType::Unknown => vec![],
+        }
+    }
+
     pub(crate) fn type_info_size(&self) -> usize {
         let ty_size = mem::size_of::<btf_type>();
 
@@ -406,7 +467,8 @@ mod tests {
             0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00,
             0x00, 0x00,
         ];
-        match unsafe { BtfType::read(data, endianness) } {
+        let got = unsafe { BtfType::read(data, endianness) };
+        match got {
             Ok(BtfType::Int(ty, nr_bits)) => {
                 assert_eq!(ty.name_off, 1);
                 assert_eq!(nr_bits, 64);
@@ -414,6 +476,8 @@ mod tests {
             Ok(t) => panic!("expected int type, got {:#?}", t),
             Err(_) => panic!("unexpected error"),
         }
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2.as_slice())
     }
 
     #[test]
@@ -422,11 +486,14 @@ mod tests {
         let data: &[u8] = &[
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x00, 0x00, 0x00,
         ];
-        match unsafe { BtfType::read(data, endianness) } {
+        let got = unsafe { BtfType::read(data, endianness) };
+        match got {
             Ok(BtfType::Ptr(_)) => {}
             Ok(t) => panic!("expected ptr type, got {:#?}", t),
             Err(_) => panic!("unexpected error"),
         }
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2.as_slice())
     }
 
     #[test]
@@ -436,11 +503,14 @@ mod tests {
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
             0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
         ];
-        match unsafe { BtfType::read(data, endianness) } {
+        let got = unsafe { BtfType::read(data, endianness) };
+        match got {
             Ok(BtfType::Array(_, _)) => {}
             Ok(t) => panic!("expected array type, got {:#?}", t),
             Err(_) => panic!("unexpected error"),
         }
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2.as_slice())
     }
 
     #[test]
@@ -450,11 +520,14 @@ mod tests {
             0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x47, 0x02,
             0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         ];
-        match unsafe { BtfType::read(data, endianness) } {
+        let got = unsafe { BtfType::read(data, endianness) };
+        match got {
             Ok(BtfType::Struct(_, _)) => {}
             Ok(t) => panic!("expected struct type, got {:#?}", t),
             Err(_) => panic!("unexpected error"),
         }
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2.as_slice())
     }
 
     #[test]
@@ -464,11 +537,14 @@ mod tests {
             0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x04, 0x00, 0x00, 0x00, 0x0d, 0x04,
             0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         ];
-        match unsafe { BtfType::read(data, endianness) } {
+        let got = unsafe { BtfType::read(data, endianness) };
+        match got {
             Ok(BtfType::Union(_, _)) => {}
             Ok(t) => panic!("expected union type, got {:#?}", t),
             Err(_) => panic!("unexpected error"),
         }
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2.as_slice())
     }
 
     #[test]
@@ -478,11 +554,14 @@ mod tests {
             0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x06, 0x04, 0x00, 0x00, 0x00, 0xc9, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
         ];
-        match unsafe { BtfType::read(data, endianness) } {
+        let got = unsafe { BtfType::read(data, endianness) };
+        match got {
             Ok(BtfType::Enum(_, _)) => {}
             Ok(t) => panic!("expected enum type, got {:#?}", t),
             Err(_) => panic!("unexpected error"),
         }
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2.as_slice())
     }
 
     #[test]
@@ -491,11 +570,14 @@ mod tests {
         let data: &[u8] = &[
             0x0b, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
         ];
-        match unsafe { BtfType::read(data, endianness) } {
+        let got = unsafe { BtfType::read(data, endianness) };
+        match got {
             Ok(BtfType::Fwd(_)) => {}
             Ok(t) => panic!("expected fwd type, got {:#?}", t),
             Err(_) => panic!("unexpected error"),
         }
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2.as_slice())
     }
 
     #[test]
@@ -504,11 +586,14 @@ mod tests {
         let data: &[u8] = &[
             0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0b, 0x00, 0x00, 0x00,
         ];
-        match unsafe { BtfType::read(data, endianness) } {
+        let got = unsafe { BtfType::read(data, endianness) };
+        match got {
             Ok(BtfType::Typedef(_)) => {}
             Ok(t) => panic!("expected typedef type, got {:#?}", t),
             Err(_) => panic!("unexpected error"),
         }
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2.as_slice())
     }
 
     #[test]
@@ -517,11 +602,14 @@ mod tests {
         let data: &[u8] = &[
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x24, 0x00, 0x00, 0x00,
         ];
-        match unsafe { BtfType::read(data, endianness) } {
+        let got = unsafe { BtfType::read(data, endianness) };
+        match got {
             Ok(BtfType::Volatile(_)) => {}
             Ok(t) => panic!("expected volatile type, got {:#?}", t),
             Err(_) => panic!("unexpected error"),
         }
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2.as_slice())
     }
 
     #[test]
@@ -530,11 +618,14 @@ mod tests {
         let data: &[u8] = &[
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00,
         ];
-        match unsafe { BtfType::read(data, endianness) } {
+        let got = unsafe { BtfType::read(data, endianness) };
+        match got {
             Ok(BtfType::Const(_)) => {}
             Ok(t) => panic!("expected const type, got {:#?}", t),
             Err(_) => panic!("unexpected error"),
         }
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2.as_slice())
     }
 
     #[test]
@@ -543,11 +634,14 @@ mod tests {
         let data: &[u8] = &[
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x04, 0x00, 0x00, 0x00,
         ];
-        match unsafe { BtfType::read(data, endianness) } {
+        let got = unsafe { BtfType::read(data, endianness) };
+        match got {
             Ok(BtfType::Restrict(_)) => {}
             Ok(t) => panic!("expected restrict type gpt {:#?}", t),
             Err(_) => panic!("unexpected error"),
         }
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2.as_slice())
     }
 
     #[test]
@@ -556,11 +650,14 @@ mod tests {
         let data: &[u8] = &[
             0x17, 0x8b, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xf0, 0xe4, 0x00, 0x00,
         ];
-        match unsafe { BtfType::read(data, endianness) } {
+        let got = unsafe { BtfType::read(data, endianness) };
+        match got {
             Ok(BtfType::Func(_)) => {}
             Ok(t) => panic!("expected func type gpt {:#?}", t),
             Err(_) => panic!("unexpected error"),
         }
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2.as_slice())
     }
 
     #[test]
@@ -570,11 +667,14 @@ mod tests {
             0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
         ];
-        match unsafe { BtfType::read(data, endianness) } {
+        let got = unsafe { BtfType::read(data, endianness) };
+        match got {
             Ok(BtfType::FuncProto(_, _)) => {}
             Ok(t) => panic!("expected func_proto type, got {:#?}", t),
             Err(_) => panic!("unexpected error"),
         }
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2.as_slice())
     }
 
     #[test]
@@ -585,11 +685,14 @@ mod tests {
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00,
         ];
-        match unsafe { BtfType::read(data, endianness) } {
+        let got = unsafe { BtfType::read(data, endianness) };
+        match got {
             Ok(BtfType::Var(_, _)) => {}
             Ok(t) => panic!("expected var type, got {:#?}", t),
             Err(_) => panic!("unexpected error"),
-        }
+        };
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2.as_slice())
     }
 
     #[test]
@@ -600,11 +703,14 @@ mod tests {
             0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         ];
-        match unsafe { BtfType::read(data, endianness) } {
+        let got = unsafe { BtfType::read(data, endianness) };
+        match got {
             Ok(BtfType::DataSec(_, _)) => {}
             Ok(t) => panic!("expected datasec type, got {:#?}", t),
             Err(_) => panic!("unexpected error"),
         }
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2.as_slice())
     }
 
     #[test]
@@ -613,10 +719,13 @@ mod tests {
         let data: &[u8] = &[
             0x78, 0xfd, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00,
         ];
-        match unsafe { BtfType::read(data, endianness) } {
+        let got = unsafe { BtfType::read(data, endianness) };
+        match got {
             Ok(BtfType::Float(_)) => {}
             Ok(t) => panic!("expected float type, got {:#?}", t),
             Err(_) => panic!("unexpected error"),
         }
+        let data2 = got.unwrap().to_bytes();
+        assert_eq!(data, data2.as_slice())
     }
 }