Browse Source

Merge pull request #974 from Billy99/billy99-arch-ppc64-s390x

aya: add archs powerpc64 and s390x to aya
Alessandro Decina 6 months ago
parent
commit
ab5e688

+ 6 - 0
.cargo/config.toml

@@ -9,3 +9,9 @@ linker = "arm-linux-gnueabihf-gcc"
 
 [target.aarch64-unknown-linux-musl]
 linker = "aarch64-linux-musl-gcc"
+
+[target.powerpc64le-unknown-linux-gnu]
+linker = "powerpc64le-linux-gnu-gcc"
+
+[target.s390x-unknown-linux-gnu]
+linker = "s390x-linux-gnu-gcc"

+ 4 - 0
.github/workflows/ci.yml

@@ -72,6 +72,8 @@ jobs:
           - aarch64-unknown-linux-gnu
           - armv7-unknown-linux-gnueabi
           - riscv64gc-unknown-linux-gnu
+          - powerpc64le-unknown-linux-gnu
+          - s390x-unknown-linux-gnu
     runs-on: ubuntu-22.04
     steps:
       - uses: actions/checkout@v4
@@ -135,6 +137,8 @@ jobs:
           - aarch64
           - arm
           - riscv64
+          - powerpc64
+          - s390x
         target:
           - bpfel-unknown-none
           - bpfeb-unknown-none

+ 1 - 1
Cargo.toml

@@ -40,7 +40,7 @@ default-members = [
 
     # ebpf crates are omitted; they must be built with:
     # --target bpfe{b,l}-unknown-none
-    # CARGO_CFG_BPF_TARGET_ARCH={x86_64,aarch64,arm,riscv64}
+    # CARGO_CFG_BPF_TARGET_ARCH={x86_64,aarch64,arm,riscv64,powerpc64,s390x}
 ]
 
 [workspace.package]

+ 5 - 0
aya-log/src/lib.rs

@@ -997,9 +997,14 @@ mod test {
         len += "ipv6: ".write(&mut input[len..]).unwrap().get();
         len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get();
         // 2001:db8::1:1 as u16 array
+        #[cfg(target_endian = "little")]
         let ipv6_arr: [u16; 8] = [
             0x2001, 0x0db8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001,
         ];
+        #[cfg(target_endian = "big")]
+        let ipv6_arr: [u16; 8] = [
+            0x0120, 0xb80d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0100,
+        ];
         len += ipv6_arr.write(&mut input[len..]).unwrap().get();
 
         _ = len;

+ 131 - 21
aya-obj/src/btf/btf.rs

@@ -1110,11 +1110,18 @@ mod tests {
 
     #[test]
     fn test_parse_header() {
-        let data: &[u8] = &[
-            0x9f, 0xeb, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x54,
-            0x2a, 0x00, 0x64, 0x54, 0x2a, 0x00, 0x10, 0x64, 0x1c, 0x00,
-        ];
-        let header = unsafe { read_btf_header(data) };
+        let header = btf_header {
+            magic: 0xeb9f,
+            version: 0x01,
+            flags: 0x00,
+            hdr_len: 0x18,
+            type_off: 0x00,
+            type_len: 0x2a5464,
+            str_off: 0x2a5464,
+            str_len: 0x1c6410,
+        };
+        let data = unsafe { bytes_of::<btf_header>(&header).to_vec() };
+        let header = unsafe { read_btf_header(&data) };
         assert_eq!(header.magic, 0xeb9f);
         assert_eq!(header.version, 0x01);
         assert_eq!(header.flags, 0x00);
@@ -1129,6 +1136,7 @@ mod tests {
     fn test_parse_btf() {
         // this generated BTF data is from an XDP program that simply returns XDP_PASS
         // compiled using clang
+        #[cfg(target_endian = "little")]
         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,
@@ -1168,35 +1176,135 @@ mod tests {
             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,
         ];
+        #[cfg(target_endian = "big")]
+        let data: &[u8] = &[
+            0xeb, 0x9f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x01, 0x0c, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0x00,
+            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00,
+            0x00, 0x06, 0x00, 0x00, 0x00, 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, 0x30, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x4e, 0x08, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
+            0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x01,
+            0x00, 0x00, 0x00, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00,
+            0x00, 0x20, 0x00, 0x00, 0x00, 0x69, 0x0c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05,
+            0x00, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
+            0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+            0x00, 0xbc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20,
+            0x00, 0x00, 0x00, 0xd0, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+            0x00, 0x01, 0x00, 0x00, 0x00, 0xd9, 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 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,
+        ];
         assert_eq!(data.len(), 517);
         let btf = Btf::parse(data, Endianness::default()).unwrap_or_else(|e| panic!("{}", e));
         let data2 = btf.to_bytes();
         assert_eq!(data2.len(), 517);
         assert_eq!(data, data2);
 
-        let ext_data: &[u8] = &[
-            0x9f, 0xeb, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00,
-            0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x01, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
-            0x72, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x00,
-            0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x05, 0x2c, 0x00, 0x00,
-        ];
+        const FUNC_LEN: u32 = 0x14;
+        const LINE_INFO_LEN: u32 = 0x1c;
+        const CORE_RELO_LEN: u32 = 0;
+        const DATA_LEN: u32 = (FUNC_LEN + LINE_INFO_LEN + CORE_RELO_LEN) / 4;
+        struct TestStruct {
+            _header: btf_ext_header,
+            _data: [u32; DATA_LEN as usize],
+        }
+        let test_data = TestStruct {
+            _header: btf_ext_header {
+                magic: 0xeb9f,
+                version: 1,
+                flags: 0,
+                hdr_len: 0x20,
+                func_info_off: 0,
+                func_info_len: FUNC_LEN,
+                line_info_off: FUNC_LEN,
+                line_info_len: LINE_INFO_LEN,
+                core_relo_off: FUNC_LEN + LINE_INFO_LEN,
+                core_relo_len: CORE_RELO_LEN,
+            },
+            _data: [
+                0x00000008u32,
+                0x00000072u32,
+                0x00000001u32,
+                0x00000000u32,
+                0x00000007u32,
+                0x00000010u32,
+                0x00000072u32,
+                0x00000001u32,
+                0x00000000u32,
+                0x0000007bu32,
+                0x000000a2u32,
+                0x00002c05u32,
+            ],
+        };
+        let ext_data = unsafe { bytes_of::<TestStruct>(&test_data).to_vec() };
 
         assert_eq!(ext_data.len(), 80);
-        let _: BtfExt = BtfExt::parse(ext_data, Endianness::default(), &btf)
+        let _: BtfExt = BtfExt::parse(&ext_data, Endianness::default(), &btf)
             .unwrap_or_else(|e| panic!("{}", e));
     }
 
     #[test]
     fn parsing_older_ext_data() {
-        let btf_data = [
-            159, 235, 1, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
-        ];
-        let btf_ext_data = [
-            159, 235, 1, 0, 24, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0,
-            0, 16, 0, 0, 0,
-        ];
+        const TYPE_LEN: u32 = 0;
+        const STR_LEN: u32 = 1;
+        struct BtfTestStruct {
+            _header: btf_header,
+            _data: [u8; (TYPE_LEN + STR_LEN) as usize],
+        }
+        let btf_test_data = BtfTestStruct {
+            _header: btf_header {
+                magic: 0xeb9f,
+                version: 0x01,
+                flags: 0x00,
+                hdr_len: 24,
+                type_off: 0,
+                type_len: TYPE_LEN,
+                str_off: TYPE_LEN,
+                str_len: TYPE_LEN + STR_LEN,
+            },
+            _data: [0x00u8],
+        };
+        let btf_data = unsafe { bytes_of::<BtfTestStruct>(&btf_test_data).to_vec() };
+
+        const FUNC_INFO_LEN: u32 = 4;
+        const LINE_INFO_LEN: u32 = 4;
+        const CORE_RELO_LEN: u32 = 16;
+        let ext_header = btf_ext_header {
+            magic: 0xeb9f,
+            version: 1,
+            flags: 0,
+            hdr_len: 24,
+            func_info_off: 0,
+            func_info_len: FUNC_INFO_LEN,
+            line_info_off: FUNC_INFO_LEN,
+            line_info_len: LINE_INFO_LEN,
+            core_relo_off: FUNC_INFO_LEN + LINE_INFO_LEN,
+            core_relo_len: CORE_RELO_LEN,
+        };
+        let btf_ext_data = unsafe { bytes_of::<btf_ext_header>(&ext_header).to_vec() };
+
         let btf = Btf::parse(&btf_data, Endianness::default()).unwrap();
         let btf_ext = BtfExt::parse(&btf_ext_data, Endianness::default(), &btf).unwrap();
         assert_eq!(btf_ext.func_info_rec_size(), 8);
@@ -1701,9 +1809,11 @@ mod tests {
         Btf::parse(&raw, Endianness::default()).unwrap();
     }
 
+    // Not possible to emulate file system file "/sys/kernel/btf/vmlinux" as big endian, so skip
     #[test]
     #[cfg(feature = "std")]
     #[cfg_attr(miri, ignore = "`open` not available when isolation is enabled")]
+    #[cfg(target_endian = "little")]
     fn test_read_btf_from_sys_fs() {
         let btf = Btf::parse_file("/sys/kernel/btf/vmlinux", Endianness::default()).unwrap();
         let task_struct_id = btf

+ 1 - 1
aya-obj/src/btf/relocation.rs

@@ -1215,7 +1215,7 @@ impl ComputedRelocation {
             }
             #[cfg(target_endian = "big")]
             FieldLShift64 => {
-                value.value = (8 - byte_size) * 8 + (bit_off - byte_off * 8);
+                value.value = ((8 - byte_size) * 8 + (bit_off - byte_off * 8)) as u64;
             }
             FieldRShift64 => {
                 value.value = 64 - bit_size as u64;

+ 74 - 96
aya-obj/src/btf/types.rs

@@ -662,7 +662,8 @@ pub struct Union {
 
 impl Union {
     pub(crate) fn new(name_offset: u32, size: u32, members: Vec<BtfMember>) -> Self {
-        let info = (BtfKind::Union as u32) << 24;
+        let mut info = (BtfKind::Union as u32) << 24;
+        info |= (members.len() as u32) & 0xFFFF;
         Self {
             name_offset,
             info,
@@ -1577,10 +1578,8 @@ mod tests {
     #[test]
     fn test_read_btf_type_int() {
         let endianness = Endianness::default();
-        let data: &[u8] = &[
-            0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00,
-            0x00, 0x00,
-        ];
+        let bpf_type = BtfType::Int(Int::new(1, 8, IntEncoding::None, 0));
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Int(new @ Int {
             name_offset,
             info: _,
@@ -1594,42 +1593,11 @@ mod tests {
         });
     }
 
-    #[test]
-    fn test_write_btf_long_unsigned_int() {
-        let data: &[u8] = &[
-            0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00,
-            0x00, 0x00,
-        ];
-        let int = Int::new(1, 8, IntEncoding::None, 0);
-        assert_eq!(int.to_bytes(), data);
-    }
-
-    #[test]
-    fn test_write_btf_uchar() {
-        let data: &[u8] = &[
-            0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00,
-            0x00, 0x00,
-        ];
-        let int = Int::new(0x13, 1, IntEncoding::None, 0);
-        assert_eq!(int.to_bytes(), data);
-    }
-
-    #[test]
-    fn test_write_btf_signed_short_int() {
-        let data: &[u8] = &[
-            0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00,
-            0x00, 0x01,
-        ];
-        let int = Int::new(0x4a, 2, IntEncoding::Signed, 0);
-        assert_eq!(int.to_bytes(), data);
-    }
-
     #[test]
     fn test_read_btf_type_ptr() {
         let endianness = Endianness::default();
-        let data: &[u8] = &[
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x00, 0x00, 0x00,
-        ];
+        let bpf_type = BtfType::Ptr(Ptr::new(0, 0x06));
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Ptr(got) => {
             assert_eq!(got.to_bytes(), data);
         });
@@ -1638,10 +1606,8 @@ mod tests {
     #[test]
     fn test_read_btf_type_array() {
         let endianness = Endianness::default();
-        let data: &[u8] = &[
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
-            0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-        ];
+        let bpf_type = BtfType::Array(Array::new(0, 1, 0x12, 2));
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Array(got) => {
             assert_eq!(got.to_bytes(), data);
         });
@@ -1650,10 +1616,13 @@ mod tests {
     #[test]
     fn test_read_btf_type_struct() {
         let endianness = Endianness::default();
-        let data: &[u8] = &[
-            0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x47, 0x02,
-            0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        ];
+        let members = vec![BtfMember {
+            name_offset: 0x0247,
+            btf_type: 0x12,
+            offset: 0,
+        }];
+        let bpf_type = BtfType::Struct(Struct::new(0, members, 4));
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Struct(got) => {
             assert_eq!(got.to_bytes(), data);
         });
@@ -1662,10 +1631,13 @@ mod tests {
     #[test]
     fn test_read_btf_type_union() {
         let endianness = Endianness::default();
-        let data: &[u8] = &[
-            0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x04, 0x00, 0x00, 0x00, 0x0d, 0x04,
-            0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        ];
+        let members = vec![BtfMember {
+            name_offset: 0x040d,
+            btf_type: 0x68,
+            offset: 0,
+        }];
+        let bpf_type = BtfType::Union(Union::new(0, 4, members));
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Union(got) => {
             assert_eq!(got.to_bytes(), data);
         });
@@ -1674,10 +1646,11 @@ mod tests {
     #[test]
     fn test_read_btf_type_enum() {
         let endianness = Endianness::default();
-        let data: &[u8] = &[
-            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,
-        ];
+        let enum1 = BtfEnum::new(0xc9, 0);
+        let enum2 = BtfEnum::new(0xcf, 1);
+        let variants = vec![enum1, enum2];
+        let bpf_type = BtfType::Enum(Enum::new(0, false, variants));
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Enum(got) => {
             assert_eq!(got.to_bytes(), data);
         });
@@ -1686,9 +1659,13 @@ mod tests {
     #[test]
     fn test_read_btf_type_fwd() {
         let endianness = Endianness::default();
-        let data: &[u8] = &[
-            0x0b, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
-        ];
+        let info = (BtfKind::Fwd as u32) << 24;
+        let bpf_type = BtfType::Fwd(Fwd {
+            name_offset: 0x550b,
+            info,
+            _unused: 0,
+        });
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Fwd(got) => {
             assert_eq!(got.to_bytes(), data);
         });
@@ -1697,9 +1674,8 @@ mod tests {
     #[test]
     fn test_read_btf_type_typedef() {
         let endianness = Endianness::default();
-        let data: &[u8] = &[
-            0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0b, 0x00, 0x00, 0x00,
-        ];
+        let bpf_type = BtfType::Typedef(Typedef::new(0x31, 0x0b));
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Typedef(got) => {
             assert_eq!(got.to_bytes(), data);
         });
@@ -1708,9 +1684,13 @@ mod tests {
     #[test]
     fn test_read_btf_type_volatile() {
         let endianness = Endianness::default();
-        let data: &[u8] = &[
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x24, 0x00, 0x00, 0x00,
-        ];
+        let info = (BtfKind::Volatile as u32) << 24;
+        let bpf_type = BtfType::Volatile(Volatile {
+            name_offset: 0,
+            info,
+            btf_type: 0x24,
+        });
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Volatile(got) => {
             assert_eq!(got.to_bytes(), data);
         });
@@ -1719,9 +1699,8 @@ mod tests {
     #[test]
     fn test_read_btf_type_const() {
         let endianness = Endianness::default();
-        let data: &[u8] = &[
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00,
-        ];
+        let bpf_type = BtfType::Const(Const::new(1));
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Const(got) => {
             assert_eq!(got.to_bytes(), data);
         });
@@ -1730,9 +1709,13 @@ mod tests {
     #[test]
     fn test_read_btf_type_restrict() {
         let endianness = Endianness::default();
-        let data: &[u8] = &[
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x04, 0x00, 0x00, 0x00,
-        ];
+        let info = (BtfKind::Restrict as u32) << 24;
+        let bpf_type = BtfType::Restrict(Restrict {
+            name_offset: 0,
+            _info: info,
+            btf_type: 4,
+        });
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Restrict(got) => {
             assert_eq!(got.to_bytes(), data);
         });
@@ -1741,9 +1724,8 @@ mod tests {
     #[test]
     fn test_read_btf_type_func() {
         let endianness = Endianness::default();
-        let data: &[u8] = &[
-            0x17, 0x8b, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xf0, 0xe4, 0x00, 0x00,
-        ];
+        let bpf_type = BtfType::Func(Func::new(0x000f8b17, 0xe4f0, FuncLinkage::Global));
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Func(got) => {
             assert_eq!(got.to_bytes(), data);
         });
@@ -1752,10 +1734,12 @@ mod tests {
     #[test]
     fn test_read_btf_type_func_proto() {
         let endianness = Endianness::default();
-        let data: &[u8] = &[
-            0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
-        ];
+        let params = vec![BtfParam {
+            name_offset: 0,
+            btf_type: 0x12,
+        }];
+        let bpf_type = BtfType::FuncProto(FuncProto::new(params, 0));
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::FuncProto(got) => {
             assert_eq!(got.to_bytes(), data);
         });
@@ -1765,10 +1749,8 @@ mod tests {
     fn test_read_btf_type_func_var() {
         let endianness = Endianness::default();
         // NOTE: There was no data in /sys/kernell/btf/vmlinux for this type
-        let data: &[u8] = &[
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00,
-        ];
+        let bpf_type = BtfType::Var(Var::new(0, 0xf0, VarLinkage::Static));
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Var(got) => {
             assert_eq!(got.to_bytes(), data);
         });
@@ -1777,10 +1759,13 @@ mod tests {
     #[test]
     fn test_read_btf_type_func_datasec() {
         let endianness = Endianness::default();
-        let data: &[u8] = &[
-            0xd9, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-        ];
+        let entries = vec![DataSecEntry {
+            btf_type: 11,
+            offset: 0,
+            size: 4,
+        }];
+        let bpf_type = BtfType::DataSec(DataSec::new(0xd9, entries, 0));
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::DataSec(DataSec {
             name_offset: _,
             info: _,
@@ -1802,9 +1787,8 @@ mod tests {
     #[test]
     fn test_read_btf_type_float() {
         let endianness = Endianness::default();
-        let data: &[u8] = &[
-            0x78, 0xfd, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00,
-        ];
+        let bpf_type = BtfType::Float(Float::new(0x02fd, 8));
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Float(got) => {
             assert_eq!(got.to_bytes(), data);
         });
@@ -1856,15 +1840,9 @@ mod tests {
     #[test]
     pub fn test_read_btf_type_enum64() {
         let endianness = Endianness::default();
-        let data: &[u8] = &[
-            0x00, 0x00, 0x00, 0x00, // name offset
-            0x01, 0x00, 0x00, 0x13, // info: vlen, type_kind
-            0x08, 0x00, 0x00, 0x00, // size
-            0xd7, 0x06, 0x00, 0x00, // enum variant name offset
-            0xbb, 0xbb, 0xbb, 0xbb, // enum variant low
-            0xaa, 0xaa, 0xaa, 0xaa, // enum variant high
-        ];
-
+        let variants = vec![BtfEnum64::new(0, 0xbbbbbbbbaaaaaaaau64)];
+        let bpf_type = BtfType::Enum64(Enum64::new(0, false, variants));
+        let data: &[u8] = &bpf_type.to_bytes();
         assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Enum64(got) => {
             assert_eq!(got.to_bytes(), data);
         });

+ 8 - 0
aya-obj/src/generated/mod.rs

@@ -13,8 +13,12 @@ mod btf_internal_bindings;
 mod linux_bindings_aarch64;
 #[cfg(target_arch = "arm")]
 mod linux_bindings_armv7;
+#[cfg(target_arch = "powerpc64")]
+mod linux_bindings_powerpc64;
 #[cfg(target_arch = "riscv64")]
 mod linux_bindings_riscv64;
+#[cfg(target_arch = "s390x")]
+mod linux_bindings_s390x;
 #[cfg(target_arch = "x86_64")]
 mod linux_bindings_x86_64;
 
@@ -25,7 +29,11 @@ pub use btf_internal_bindings::{bpf_core_relo, bpf_core_relo_kind, btf_ext_heade
 pub use linux_bindings_aarch64::*;
 #[cfg(target_arch = "arm")]
 pub use linux_bindings_armv7::*;
+#[cfg(target_arch = "powerpc64")]
+pub use linux_bindings_powerpc64::*;
 #[cfg(target_arch = "riscv64")]
 pub use linux_bindings_riscv64::*;
+#[cfg(target_arch = "s390x")]
+pub use linux_bindings_s390x::*;
 #[cfg(target_arch = "x86_64")]
 pub use linux_bindings_x86_64::*;

+ 98 - 13
aya-obj/src/obj.rs

@@ -1396,6 +1396,7 @@ mod tests {
     use assert_matches::assert_matches;
 
     use super::*;
+    use crate::generated::btf_ext_header;
 
     const FAKE_INS_LEN: u64 = 8;
 
@@ -1594,22 +1595,32 @@ mod tests {
     #[test]
     fn sanitizes_empty_btf_files_to_none() {
         let mut obj = fake_obj();
-        obj.parse_section(fake_section(
-            EbpfSectionKind::Btf,
-            ".BTF",
-            &[
-                159, 235, 1, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
-            ],
-            None,
-        ))
-        .unwrap();
+
+        let btf = Btf::new();
+        let btf_bytes = btf.to_bytes();
+        obj.parse_section(fake_section(EbpfSectionKind::Btf, ".BTF", &btf_bytes, None))
+            .unwrap();
+
+        const FUNC_INFO_LEN: u32 = 4;
+        const LINE_INFO_LEN: u32 = 4;
+        const CORE_RELO_LEN: u32 = 16;
+        let ext_header = btf_ext_header {
+            magic: 0xeb9f,
+            version: 1,
+            flags: 0,
+            hdr_len: 24,
+            func_info_off: 0,
+            func_info_len: FUNC_INFO_LEN,
+            line_info_off: FUNC_INFO_LEN,
+            line_info_len: LINE_INFO_LEN,
+            core_relo_off: FUNC_INFO_LEN + LINE_INFO_LEN,
+            core_relo_len: CORE_RELO_LEN,
+        };
+        let btf_ext_bytes = bytes_of::<btf_ext_header>(&ext_header).to_vec();
         obj.parse_section(fake_section(
             EbpfSectionKind::BtfExt,
             ".BTF.ext",
-            &[
-                159, 235, 1, 0, 24, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0,
-                0, 0, 16, 0, 0, 0,
-            ],
+            &btf_ext_bytes,
             None,
         ))
         .unwrap();
@@ -2588,6 +2599,7 @@ mod tests {
         // generated from:
         // objcopy --dump-section .BTF=test.btf ./target/bpfel-unknown-none/debug/multimap-btf.bpf.o
         // hexdump -v  -e '7/1 "0x%02X, " 1/1  " 0x%02X,\n"' test.btf
+        #[cfg(target_endian = "little")]
         let data: &[u8] = &[
             0x9F, 0xEB, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x01,
             0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0xCC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -2660,6 +2672,79 @@ mod tests {
             0x63, 0x68, 0x61, 0x72, 0x00, 0x5F, 0x6C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, 0x00,
             0x2E, 0x6D, 0x61, 0x70, 0x73, 0x00, 0x6C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, 0x00,
         ];
+        #[cfg(target_endian = "big")]
+        let data: &[u8] = &[
+            0xEB, 0x9F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x01, 0xF0, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x00, 0x00, 0x00,
+            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
+            0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+            0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x19, 0x08, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x0A, 0x00, 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+            0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+            0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x45,
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00,
+            0x00, 0x05, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x08,
+            0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00,
+            0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D,
+            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00,
+            0x00, 0x20, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
+            0x00, 0x4E, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x54,
+            0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x66, 0x0E, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00,
+            0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x11,
+            0x00, 0x00, 0x00, 0x70, 0x0C, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
+            0x01, 0xB0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x08,
+            0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0xB5,
+            0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+            0x01, 0xBE, 0x0F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0xC4, 0x0F, 0x00, 0x00, 0x01,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x04, 0x00, 0x69, 0x6E, 0x74, 0x00, 0x5F, 0x5F, 0x41, 0x52, 0x52, 0x41, 0x59,
+            0x5F, 0x53, 0x49, 0x5A, 0x45, 0x5F, 0x54, 0x59, 0x50, 0x45, 0x5F, 0x5F, 0x00, 0x5F,
+            0x5F, 0x75, 0x33, 0x32, 0x00, 0x75, 0x6E, 0x73, 0x69, 0x67, 0x6E, 0x65, 0x64, 0x20,
+            0x69, 0x6E, 0x74, 0x00, 0x5F, 0x5F, 0x75, 0x36, 0x34, 0x00, 0x75, 0x6E, 0x73, 0x69,
+            0x67, 0x6E, 0x65, 0x64, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x6C, 0x6F, 0x6E, 0x67,
+            0x00, 0x74, 0x79, 0x70, 0x65, 0x00, 0x6B, 0x65, 0x79, 0x00, 0x76, 0x61, 0x6C, 0x75,
+            0x65, 0x00, 0x6D, 0x61, 0x78, 0x5F, 0x65, 0x6E, 0x74, 0x72, 0x69, 0x65, 0x73, 0x00,
+            0x6D, 0x61, 0x70, 0x5F, 0x31, 0x00, 0x6D, 0x61, 0x70, 0x5F, 0x32, 0x00, 0x63, 0x74,
+            0x78, 0x00, 0x62, 0x70, 0x66, 0x5F, 0x70, 0x72, 0x6F, 0x67, 0x00, 0x74, 0x72, 0x61,
+            0x63, 0x65, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x00, 0x2F, 0x76, 0x61, 0x72, 0x2F, 0x68,
+            0x6F, 0x6D, 0x65, 0x2F, 0x64, 0x61, 0x76, 0x65, 0x2F, 0x64, 0x65, 0x76, 0x2F, 0x61,
+            0x79, 0x61, 0x2D, 0x72, 0x73, 0x2F, 0x61, 0x79, 0x61, 0x2F, 0x74, 0x65, 0x73, 0x74,
+            0x2F, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2D, 0x65,
+            0x62, 0x70, 0x66, 0x2F, 0x73, 0x72, 0x63, 0x2F, 0x62, 0x70, 0x66, 0x2F, 0x6D, 0x75,
+            0x6C, 0x74, 0x69, 0x6D, 0x61, 0x70, 0x2D, 0x62, 0x74, 0x66, 0x2E, 0x62, 0x70, 0x66,
+            0x2E, 0x63, 0x00, 0x69, 0x6E, 0x74, 0x20, 0x62, 0x70, 0x66, 0x5F, 0x70, 0x72, 0x6F,
+            0x67, 0x28, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x2A, 0x63, 0x74, 0x78, 0x29, 0x00, 0x09,
+            0x5F, 0x5F, 0x75, 0x33, 0x32, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x3D, 0x20, 0x30, 0x3B,
+            0x00, 0x09, 0x5F, 0x5F, 0x75, 0x36, 0x34, 0x20, 0x74, 0x77, 0x65, 0x6E, 0x74, 0x79,
+            0x5F, 0x66, 0x6F, 0x75, 0x72, 0x20, 0x3D, 0x20, 0x32, 0x34, 0x3B, 0x00, 0x09, 0x5F,
+            0x5F, 0x75, 0x36, 0x34, 0x20, 0x66, 0x6F, 0x72, 0x74, 0x79, 0x5F, 0x74, 0x77, 0x6F,
+            0x20, 0x3D, 0x20, 0x34, 0x32, 0x3B, 0x00, 0x20, 0x20, 0x20, 0x20, 0x62, 0x70, 0x66,
+            0x5F, 0x6D, 0x61, 0x70, 0x5F, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5F, 0x65, 0x6C,
+            0x65, 0x6D, 0x28, 0x26, 0x6D, 0x61, 0x70, 0x5F, 0x31, 0x2C, 0x20, 0x26, 0x6B, 0x65,
+            0x79, 0x2C, 0x20, 0x26, 0x74, 0x77, 0x65, 0x6E, 0x74, 0x79, 0x5F, 0x66, 0x6F, 0x75,
+            0x72, 0x2C, 0x20, 0x42, 0x50, 0x46, 0x5F, 0x41, 0x4E, 0x59, 0x29, 0x3B, 0x00, 0x20,
+            0x20, 0x20, 0x20, 0x62, 0x70, 0x66, 0x5F, 0x6D, 0x61, 0x70, 0x5F, 0x75, 0x70, 0x64,
+            0x61, 0x74, 0x65, 0x5F, 0x65, 0x6C, 0x65, 0x6D, 0x28, 0x26, 0x6D, 0x61, 0x70, 0x5F,
+            0x32, 0x2C, 0x20, 0x26, 0x6B, 0x65, 0x79, 0x2C, 0x20, 0x26, 0x66, 0x6F, 0x72, 0x74,
+            0x79, 0x5F, 0x74, 0x77, 0x6F, 0x2C, 0x20, 0x42, 0x50, 0x46, 0x5F, 0x41, 0x4E, 0x59,
+            0x29, 0x3B, 0x00, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x30, 0x3B, 0x00,
+            0x63, 0x68, 0x61, 0x72, 0x00, 0x5F, 0x6C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, 0x00,
+            0x2E, 0x6D, 0x61, 0x70, 0x73, 0x00, 0x6C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, 0x00,
+        ];
 
         let btf_section = fake_section(EbpfSectionKind::Btf, ".BTF", data, None);
         obj.parse_section(btf_section).unwrap();

+ 17 - 2
aya/src/maps/perf/perf_buffer.rs

@@ -547,8 +547,17 @@ mod tests {
         let offset = PAGE_SIZE - mem::size_of::<perf_event_header>() - 2;
         mmapped_buf.mmap_page.data_tail = offset as u64;
         write(&mut mmapped_buf, offset, header);
-        write(&mut mmapped_buf, PAGE_SIZE - 2, 0x0004u16);
-        write(&mut mmapped_buf, 0, 0x0000u16);
+        #[cfg(target_endian = "little")]
+        {
+            write(&mut mmapped_buf, PAGE_SIZE - 2, 0x0004u16);
+            write(&mut mmapped_buf, 0, 0x0000u16);
+        }
+        #[cfg(target_endian = "big")]
+        {
+            write(&mut mmapped_buf, PAGE_SIZE - 2, 0x0000u16);
+            write(&mut mmapped_buf, 0, 0x0004u16);
+        }
+
         write(&mut mmapped_buf, 2, 0xBAADCAFEu32);
 
         let mut out_bufs = [BytesMut::with_capacity(8)];
@@ -579,13 +588,19 @@ mod tests {
                 },
                 size: mem::size_of::<u64>() as u32,
             },
+            #[cfg(target_endian = "little")]
             value: 0xCAFEBABEu32,
+            #[cfg(target_endian = "big")]
+            value: 0xBAADCAFEu32,
         };
 
         let offset = PAGE_SIZE - mem::size_of::<PerfSample<u32>>();
         mmapped_buf.mmap_page.data_tail = offset as u64;
         write(&mut mmapped_buf, offset, sample);
+        #[cfg(target_endian = "little")]
         write(&mut mmapped_buf, 0, 0xBAADCAFEu32);
+        #[cfg(target_endian = "big")]
+        write(&mut mmapped_buf, 0, 0xCAFEBABEu32);
 
         let mut out_bufs = [BytesMut::with_capacity(8)];
 

+ 50 - 0
aya/src/sys/bpf.rs

@@ -672,6 +672,11 @@ pub(crate) fn is_prog_name_supported() -> bool {
     });
     u.prog_name = name;
 
+    // The fields conforming an encoded basic instruction are stored in the following order:
+    //   opcode:8 src_reg:4 dst_reg:4 offset:16 imm:32   - In little-endian BPF.
+    //   opcode:8 dst_reg:4 src_reg:4 offset:16 imm:32   - In big-endian BPF.
+    // Multi-byte fields ('imm' and 'offset') are stored using endian order.
+    // https://www.kernel.org/doc/html/v6.4-rc7/bpf/instruction-set.html#instruction-encoding
     let prog: &[u8] = &[
         0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r0 = 0
         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit
@@ -692,6 +697,12 @@ pub(crate) fn is_probe_read_kernel_supported() -> bool {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
     let u = unsafe { &mut attr.__bindgen_anon_3 };
 
+    // The fields conforming an encoded basic instruction are stored in the following order:
+    //   opcode:8 src_reg:4 dst_reg:4 offset:16 imm:32   - In little-endian BPF.
+    //   opcode:8 dst_reg:4 src_reg:4 offset:16 imm:32   - In big-endian BPF.
+    // Multi-byte fields ('imm' and 'offset') are stored using endian order.
+    // https://www.kernel.org/doc/html/v6.4-rc7/bpf/instruction-set.html#instruction-encoding
+    #[cfg(target_endian = "little")]
     let prog: &[u8] = &[
         0xbf, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // r1 = r10
         0x07, 0x01, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, // r1 -= 8
@@ -700,6 +711,15 @@ pub(crate) fn is_probe_read_kernel_supported() -> bool {
         0x85, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, // call 113
         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit
     ];
+    #[cfg(target_endian = "big")]
+    let prog: &[u8] = &[
+        0xbf, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // r1 = r10
+        0x07, 0x10, 0x00, 0x00, 0xff, 0xff, 0xff, 0xf8, // r1 -= 8
+        0xb7, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, // r2 = 8
+        0xb7, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // r3 = 0
+        0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, // call 113
+        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit
+    ];
 
     let gpl = b"GPL\0";
     u.license = gpl.as_ptr() as u64;
@@ -716,6 +736,11 @@ pub(crate) fn is_perf_link_supported() -> bool {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
     let u = unsafe { &mut attr.__bindgen_anon_3 };
 
+    // The fields conforming an encoded basic instruction are stored in the following order:
+    //   opcode:8 src_reg:4 dst_reg:4 offset:16 imm:32   - In little-endian BPF.
+    //   opcode:8 dst_reg:4 src_reg:4 offset:16 imm:32   - In big-endian BPF.
+    // Multi-byte fields ('imm' and 'offset') are stored using endian order.
+    // https://www.kernel.org/doc/html/v6.4-rc7/bpf/instruction-set.html#instruction-encoding
     let prog: &[u8] = &[
         0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r0 = 0
         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit
@@ -746,6 +771,12 @@ pub(crate) fn is_bpf_global_data_supported() -> bool {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
     let u = unsafe { &mut attr.__bindgen_anon_3 };
 
+    // The fields conforming an encoded basic instruction are stored in the following order:
+    //   opcode:8 src_reg:4 dst_reg:4 offset:16 imm:32   - In little-endian BPF.
+    //   opcode:8 dst_reg:4 src_reg:4 offset:16 imm:32   - In big-endian BPF.
+    // Multi-byte fields ('imm' and 'offset') are stored using endian order.
+    // https://www.kernel.org/doc/html/v6.4-rc7/bpf/instruction-set.html#instruction-encoding
+    #[cfg(target_endian = "little")]
     let prog: &[u8] = &[
         0x18, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ld_pseudo r1, 0x2, 0x0
         0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, //
@@ -753,6 +784,14 @@ pub(crate) fn is_bpf_global_data_supported() -> bool {
         0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r0 = 0
         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit
     ];
+    #[cfg(target_endian = "big")]
+    let prog: &[u8] = &[
+        0x18, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, // ld_pseudo r1, 0x2, 0x0
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
+        0x7a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, // stdw [r1 + 0x0], 0x2a
+        0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r0 = 0
+        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit
+    ];
 
     let mut insns = copy_instructions(prog).unwrap();
 
@@ -793,10 +832,21 @@ pub(crate) fn is_bpf_cookie_supported() -> bool {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
     let u = unsafe { &mut attr.__bindgen_anon_3 };
 
+    // The fields conforming an encoded basic instruction are stored in the following order:
+    //   opcode:8 src_reg:4 dst_reg:4 offset:16 imm:32   - In little-endian BPF.
+    //   opcode:8 dst_reg:4 src_reg:4 offset:16 imm:32   - In big-endian BPF.
+    // Multi-byte fields ('imm' and 'offset') are stored using endian order.
+    // https://www.kernel.org/doc/html/v6.4-rc7/bpf/instruction-set.html#instruction-encoding
+    #[cfg(target_endian = "little")]
     let prog: &[u8] = &[
         0x85, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, // call bpf_get_attach_cookie
         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit
     ];
+    #[cfg(target_endian = "big")]
+    let prog: &[u8] = &[
+        0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, // call bpf_get_attach_cookie
+        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit
+    ];
 
     let gpl = b"GPL\0";
     u.license = gpl.as_ptr() as u64;

+ 1 - 1
ebpf/aya-ebpf-bindings/build.rs

@@ -9,5 +9,5 @@ fn main() {
         let arch = arch.split_once('-').map_or(&*arch, |x| x.0);
         println!("cargo:rustc-cfg=bpf_target_arch=\"{arch}\"");
     }
-    println!("cargo::rustc-check-cfg=cfg(bpf_target_arch, values(\"x86_64\",\"arm\",\"aarch64\",\"riscv64\"))");
+    println!("cargo::rustc-check-cfg=cfg(bpf_target_arch, values(\"x86_64\",\"arm\",\"aarch64\",\"riscv64\",\"powerpc64\",\"s390x\"))");
 }

+ 10 - 0
ebpf/aya-ebpf-bindings/src/lib.rs

@@ -14,13 +14,23 @@ mod aarch64;
 #[cfg(bpf_target_arch = "riscv64")]
 mod riscv64;
 
+#[cfg(bpf_target_arch = "powerpc64")]
+mod powerpc64;
+
+#[cfg(bpf_target_arch = "s390x")]
+mod s390x;
+
 mod gen {
     #[cfg(bpf_target_arch = "aarch64")]
     pub use super::aarch64::*;
     #[cfg(bpf_target_arch = "arm")]
     pub use super::armv7::*;
+    #[cfg(bpf_target_arch = "powerpc64")]
+    pub use super::powerpc64::*;
     #[cfg(bpf_target_arch = "riscv64")]
     pub use super::riscv64::*;
+    #[cfg(bpf_target_arch = "s390x")]
+    pub use super::s390x::*;
     #[cfg(bpf_target_arch = "x86_64")]
     pub use super::x86_64::*;
 }

+ 3 - 0
ebpf/aya-ebpf-bindings/src/powerpc64/mod.rs

@@ -0,0 +1,3 @@
+#![allow(clippy::all, dead_code)]
+pub mod bindings;
+pub mod helpers;

+ 3 - 0
ebpf/aya-ebpf-bindings/src/s390x/mod.rs

@@ -0,0 +1,3 @@
+#![allow(clippy::all, dead_code)]
+pub mod bindings;
+pub mod helpers;

+ 1 - 1
ebpf/aya-ebpf-cty/build.rs

@@ -9,6 +9,6 @@ fn main() {
         let arch = arch.split_once('-').map_or(&*arch, |x| x.0);
         println!("cargo:rustc-cfg=bpf_target_arch=\"{arch}\"");
     }
-    println!("cargo::rustc-check-cfg=cfg(bpf_target_arch, values(\"x86_64\",\"arm\",\"aarch64\",\"riscv64\"))");
+    println!("cargo::rustc-check-cfg=cfg(bpf_target_arch, values(\"x86_64\",\"arm\",\"aarch64\",\"riscv64\",\"powerpc64\",\"s390x\"))");
     println!("cargo::rustc-check-cfg=cfg(target_arch, values(\"asmjs\",\"nvptx\",\"xtensa\"))");
 }

+ 6 - 0
ebpf/aya-ebpf-cty/src/lib.rs

@@ -24,9 +24,15 @@ mod ad {
     #[cfg(bpf_target_arch = "aarch64")]
     pub type c_char = super::c_uchar;
 
+    #[cfg(bpf_target_arch = "powerpc64")]
+    pub type c_char = super::c_uchar;
+
     #[cfg(bpf_target_arch = "riscv64")]
     pub type c_char = super::c_uchar;
 
+    #[cfg(bpf_target_arch = "s390x")]
+    pub type c_char = super::c_uchar;
+
     #[cfg(bpf_target_arch = "x86_64")]
     pub type c_char = super::c_schar;
 }

+ 1 - 1
ebpf/aya-ebpf/build.rs

@@ -10,7 +10,7 @@ fn main() {
         let arch = arch.split_once('-').map_or(&*arch, |x| x.0);
         println!("cargo:rustc-cfg=bpf_target_arch=\"{arch}\"");
     }
-    println!("cargo::rustc-check-cfg=cfg(bpf_target_arch, values(\"x86_64\",\"arm\",\"aarch64\",\"riscv64\"))");
+    println!("cargo::rustc-check-cfg=cfg(bpf_target_arch, values(\"x86_64\",\"arm\",\"aarch64\",\"riscv64\",\"powerpc64\",\"s390x\"))");
     println!("cargo::rustc-check-cfg=cfg(unstable)");
 }
 

+ 98 - 3
ebpf/aya-ebpf/src/args.rs

@@ -1,8 +1,13 @@
-// aarch64 uses user_pt_regs instead of pt_regs
-#[cfg(not(any(bpf_target_arch = "aarch64", bpf_target_arch = "riscv64")))]
+#[cfg(any(
+    bpf_target_arch = "x86_64",
+    bpf_target_arch = "arm",
+    bpf_target_arch = "powerpc64"
+))]
 use crate::bindings::pt_regs;
-#[cfg(bpf_target_arch = "aarch64")]
+// aarch64 uses user_pt_regs instead of pt_regs
+#[cfg(any(bpf_target_arch = "aarch64", bpf_target_arch = "s390x"))]
 use crate::bindings::user_pt_regs as pt_regs;
+// riscv64 uses user_regs_struct instead of pt_regs
 #[cfg(bpf_target_arch = "riscv64")]
 use crate::bindings::user_regs_struct as pt_regs;
 use crate::{cty::c_void, helpers::bpf_probe_read};
@@ -168,6 +173,36 @@ impl<T> FromPtRegs for *const T {
     }
 }
 
+#[cfg(bpf_target_arch = "powerpc64")]
+impl<T> FromPtRegs for *const T {
+    fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
+        if n <= 7 {
+            unsafe { bpf_probe_read(&ctx.gpr[3 + n]).map(|v| v as *const _).ok() }
+        } else {
+            None
+        }
+    }
+
+    fn from_retval(ctx: &pt_regs) -> Option<Self> {
+        unsafe { bpf_probe_read(&ctx.gpr[3]).map(|v| v as *const _).ok() }
+    }
+}
+
+#[cfg(bpf_target_arch = "s390x")]
+impl<T> FromPtRegs for *const T {
+    fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
+        if n <= 4 {
+            unsafe { bpf_probe_read(&ctx.gprs[2 + n]).map(|v| v as *const _).ok() }
+        } else {
+            None
+        }
+    }
+
+    fn from_retval(ctx: &pt_regs) -> Option<Self> {
+        unsafe { bpf_probe_read(&ctx.gprs[2]).map(|v| v as *const _).ok() }
+    }
+}
+
 #[cfg(bpf_target_arch = "x86_64")]
 impl<T> FromPtRegs for *mut T {
     fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
@@ -238,6 +273,36 @@ impl<T> FromPtRegs for *mut T {
     }
 }
 
+#[cfg(bpf_target_arch = "powerpc64")]
+impl<T> FromPtRegs for *mut T {
+    fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
+        if n <= 7 {
+            unsafe { bpf_probe_read(&ctx.gpr[3 + n]).map(|v| v as *mut _).ok() }
+        } else {
+            None
+        }
+    }
+
+    fn from_retval(ctx: &pt_regs) -> Option<Self> {
+        unsafe { bpf_probe_read(&ctx.gpr[3]).map(|v| v as *mut _).ok() }
+    }
+}
+
+#[cfg(bpf_target_arch = "s390x")]
+impl<T> FromPtRegs for *mut T {
+    fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
+        if n <= 4 {
+            unsafe { bpf_probe_read(&ctx.gprs[2 + n]).map(|v| v as *mut _).ok() }
+        } else {
+            None
+        }
+    }
+
+    fn from_retval(ctx: &pt_regs) -> Option<Self> {
+        unsafe { bpf_probe_read(&ctx.gprs[2]).map(|v| v as *mut _).ok() }
+    }
+}
+
 /// Helper macro to implement [`FromPtRegs`] for a primitive type.
 macro_rules! impl_from_pt_regs {
     ($type:ident) => {
@@ -310,6 +375,36 @@ macro_rules! impl_from_pt_regs {
                 Some(ctx.ra as *const $type as _)
             }
         }
+
+        #[cfg(bpf_target_arch = "powerpc64")]
+        impl FromPtRegs for $type {
+            fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
+                if n <= 7 {
+                    Some(ctx.gpr[3 + n] as *const $type as _)
+                } else {
+                    None
+                }
+            }
+
+            fn from_retval(ctx: &pt_regs) -> Option<Self> {
+                Some(ctx.gpr[3] as *const $type as _)
+            }
+        }
+
+        #[cfg(bpf_target_arch = "s390x")]
+        impl FromPtRegs for $type {
+            fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
+                if n <= 4 {
+                    Some(ctx.gprs[2 + n] as *const $type as _)
+                } else {
+                    None
+                }
+            }
+
+            fn from_retval(ctx: &pt_regs) -> Option<Self> {
+                Some(ctx.gprs[2] as *const $type as _)
+            }
+        }
     };
 }
 

+ 8 - 2
ebpf/aya-ebpf/src/programs/probe.rs

@@ -1,9 +1,15 @@
 use core::ffi::c_void;
 
-#[cfg(not(any(bpf_target_arch = "aarch64", bpf_target_arch = "riscv64")))]
+#[cfg(any(
+    bpf_target_arch = "x86_64",
+    bpf_target_arch = "arm",
+    bpf_target_arch = "powerpc64"
+))]
 use crate::bindings::pt_regs;
-#[cfg(bpf_target_arch = "aarch64")]
+// aarch64 uses user_pt_regs instead of pt_regs
+#[cfg(any(bpf_target_arch = "aarch64", bpf_target_arch = "s390x"))]
 use crate::bindings::user_pt_regs as pt_regs;
+// riscv64 uses user_regs_struct instead of pt_regs
 #[cfg(bpf_target_arch = "riscv64")]
 use crate::bindings::user_regs_struct as pt_regs;
 use crate::{args::FromPtRegs, EbpfContext};

+ 8 - 2
ebpf/aya-ebpf/src/programs/retprobe.rs

@@ -1,9 +1,15 @@
 use core::ffi::c_void;
 
-#[cfg(not(any(bpf_target_arch = "aarch64", bpf_target_arch = "riscv64")))]
+#[cfg(any(
+    bpf_target_arch = "x86_64",
+    bpf_target_arch = "arm",
+    bpf_target_arch = "powerpc64"
+))]
 use crate::bindings::pt_regs;
-#[cfg(bpf_target_arch = "aarch64")]
+// aarch64 uses user_pt_regs instead of pt_regs
+#[cfg(any(bpf_target_arch = "aarch64", bpf_target_arch = "s390x"))]
 use crate::bindings::user_pt_regs as pt_regs;
+// riscv64 uses user_regs_struct instead of pt_regs
 #[cfg(bpf_target_arch = "riscv64")]
 use crate::bindings::user_regs_struct as pt_regs;
 use crate::{args::FromPtRegs, EbpfContext};