Repository: aya-rs/aya (language: rust)

Issue:
Allow the user to load pre-existing BPF maps from a pin point or a Raw FD 
Similar to https://github.com/cilium/ebpf 's Map APIs https://pkg.go.dev/github.com/cilium/ebpf#LoadPinnedMap and https://pkg.go.dev/github.com/cilium/ebpf#NewMapFromFD I would like the ability to load and interact with Pre-existing BPF maps which may or may not have been loaded by aya.


Discussion / hints:

Fix patch:
diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs
index bd9ce5957..3bd01c8ba 100644
--- a/aya/src/bpf.rs
+++ b/aya/src/bpf.rs
@@ -443,7 +443,7 @@ impl<'a> BpfLoader<'a> {
                         Err(_) => {
                             let fd = map.create(&name)?;
                             map.pin(&name, path).map_err(|error| MapError::PinError {
-                                name: name.to_string(),
+                                name: Some(name.to_string()),
                                 error,
                             })?;
                             fd
@@ -454,16 +454,14 @@ impl<'a> BpfLoader<'a> {
             };
             if !map.obj.data().is_empty() && map.obj.kind() != MapKind::Bss {
                 bpf_map_update_elem_ptr(fd, &0 as *const _, map.obj.data_mut().as_mut_ptr(), 0)
-                    .map_err(|(code, io_error)| MapError::SyscallError {
+                    .map_err(|(_, io_error)| MapError::SyscallError {
                         call: "bpf_map_update_elem".to_owned(),
-                        code,
                         io_error,
                     })?;
             }
             if map.obj.kind() == MapKind::Rodata {
-                bpf_map_freeze(fd).map_err(|(code, io_error)| MapError::SyscallError {
+                bpf_map_freeze(fd).map_err(|(_, io_error)| MapError::SyscallError {
                     call: "bpf_map_freeze".to_owned(),
-                    code,
                     io_error,
                 })?;
             }
diff --git a/aya/src/maps/array/array.rs b/aya/src/maps/array/array.rs
index 4e4aafd25..b1bef3e9e 100644
--- a/aya/src/maps/array/array.rs
+++ b/aya/src/maps/array/array.rs
@@ -80,10 +80,9 @@ impl<T: Deref<Target = Map>, V: Pod> Array<T, V> {
         self.check_bounds(*index)?;
         let fd = self.inner.fd_or_err()?;
 
-        let value = bpf_map_lookup_elem(fd, index, flags).map_err(|(code, io_error)| {
+        let value = bpf_map_lookup_elem(fd, index, flags).map_err(|(_, io_error)| {
             MapError::SyscallError {
                 call: "bpf_map_lookup_elem".to_owned(),
-                code,
                 io_error,
             }
         })?;
@@ -116,10 +115,9 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Array<T, V> {
     pub fn set(&mut self, index: u32, value: V, flags: u64) -> Result<(), MapError> {
         let fd = self.inner.fd_or_err()?;
         self.check_bounds(index)?;
-        bpf_map_update_elem(fd, Some(&index), &value, flags).map_err(|(code, io_error)| {
+        bpf_map_update_elem(fd, Some(&index), &value, flags).map_err(|(_, io_error)| {
             MapError::SyscallError {
                 call: "bpf_map_update_elem".to_owned(),
-                code,
                 io_error,
             }
         })?;
diff --git a/aya/src/maps/array/per_cpu_array.rs b/aya/src/maps/array/per_cpu_array.rs
index f501aeda8..99a3e7ed4 100644
--- a/aya/src/maps/array/per_cpu_array.rs
+++ b/aya/src/maps/array/per_cpu_array.rs
@@ -99,10 +99,9 @@ impl<T: Deref<Target = Map>, V: Pod> PerCpuArray<T, V> {
         self.check_bounds(*index)?;
         let fd = self.inner.fd_or_err()?;
 
-        let value = bpf_map_lookup_elem_per_cpu(fd, index, flags).map_err(|(code, io_error)| {
+        let value = bpf_map_lookup_elem_per_cpu(fd, index, flags).map_err(|(_, io_error)| {
             MapError::SyscallError {
                 call: "bpf_map_lookup_elem".to_owned(),
-                code,
                 io_error,
             }
         })?;
@@ -135,10 +134,9 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> PerCpuArray<T, V>
     pub fn set(&mut self, index: u32, values: PerCpuValues<V>, flags: u64) -> Result<(), MapError> {
         let fd = self.inner.fd_or_err()?;
         self.check_bounds(index)?;
-        bpf_map_update_elem_per_cpu(fd, &index, &values, flags).map_err(|(code, io_error)| {
+        bpf_map_update_elem_per_cpu(fd, &index, &values, flags).map_err(|(_, io_error)| {
             MapError::SyscallError {
                 call: "bpf_map_update_elem".to_owned(),
-                code,
                 io_error,
             }
         })?;
diff --git a/aya/src/maps/array/program_array.rs b/aya/src/maps/array/program_array.rs
index a16dc607b..5d02e0261 100644
--- a/aya/src/maps/array/program_array.rs
+++ b/aya/src/maps/array/program_array.rs
@@ -103,10 +103,9 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>> ProgramArray<T> {
         self.check_bounds(index)?;
         let prog_fd = program.as_raw_fd();
 
-        bpf_map_update_elem(fd, Some(&index), &prog_fd, flags).map_err(|(code, io_error)| {
+        bpf_map_update_elem(fd, Some(&index), &prog_fd, flags).map_err(|(_, io_error)| {
             MapError::SyscallError {
                 call: "bpf_map_update_elem".to_owned(),
-                code,
                 io_error,
             }
         })?;
@@ -122,9 +121,8 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>> ProgramArray<T> {
         self.check_bounds(*index)?;
         bpf_map_delete_elem(fd, index)
             .map(|_| ())
-            .map_err(|(code, io_error)| MapError::SyscallError {
+            .map_err(|(_, io_error)| MapError::SyscallError {
                 call: "bpf_map_delete_elem".to_owned(),
-                code,
                 io_error,
             })
     }
diff --git a/aya/src/maps/bloom_filter.rs b/aya/src/maps/bloom_filter.rs
index b0901df5c..47ba02078 100644
--- a/aya/src/maps/bloom_filter.rs
+++ b/aya/src/maps/bloom_filter.rs
@@ -68,9 +68,8 @@ impl<T: Deref<Target = Map>, V: Pod> BloomFilter<T, V> {
         let fd = self.inner.deref().fd_or_err()?;
 
         bpf_map_lookup_elem_ptr::<u32, _>(fd, None, &mut value, flags)
-            .map_err(|(code, io_error)| MapError::SyscallError {
+            .map_err(|(_, io_error)| MapError::SyscallError {
                 call: "bpf_map_lookup_elem".to_owned(),
-                code,
                 io_error,
             })?
             .ok_or(MapError::ElementNotFound)?;
@@ -80,12 +79,9 @@ impl<T: Deref<Target = Map>, V: Pod> BloomFilter<T, V> {
     /// Inserts a value into the map.
     pub fn insert(&self, value: V, flags: u64) -> Result<(), MapError> {
         let fd = self.inner.deref().fd_or_err()?;
-        bpf_map_push_elem(fd, &value, flags).map_err(|(code, io_error)| {
-            MapError::SyscallError {
-                call: "bpf_map_push_elem".to_owned(),
-                code,
-                io_error,
-            }
+        bpf_map_push_elem(fd, &value, flags).map_err(|(_, io_error)| MapError::SyscallError {
+            call: "bpf_map_push_elem".to_owned(),
+            io_error,
         })?;
         Ok(())
     }
@@ -254,7 +250,7 @@ mod tests {
 
         assert!(matches!(
             bloom_filter.insert(1, 0),
-            Err(MapError::SyscallError { call, code: -1, io_error }) if call == "bpf_map_push_elem" && io_error.raw_os_error() == Some(EFAULT)
+            Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_push_elem" && io_error.raw_os_error() == Some(EFAULT)
         ));
     }
 
@@ -292,7 +288,7 @@ mod tests {
 
         assert!(matches!(
             bloom_filter.contains(&1, 0),
-            Err(MapError::SyscallError { call, code: -1, io_error }) if call == "bpf_map_lookup_elem" && io_error.raw_os_error() == Some(EFAULT)
+            Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_lookup_elem" && io_error.raw_os_error() == Some(EFAULT)
         ));
     }
 
diff --git a/aya/src/maps/hash_map/hash_map.rs b/aya/src/maps/hash_map/hash_map.rs
index 5b99b0d8d..33bd6cc8d 100644
--- a/aya/src/maps/hash_map/hash_map.rs
+++ b/aya/src/maps/hash_map/hash_map.rs
@@ -61,10 +61,9 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> HashMap<T, K, V> {
     /// Returns a copy of the value associated with the key.
     pub fn get(&self, key: &K, flags: u64) -> Result<V, MapError> {
         let fd = self.inner.deref().fd_or_err()?;
-        let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(code, io_error)| {
+        let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| {
             MapError::SyscallError {
                 call: "bpf_map_lookup_elem".to_owned(),
-                code,
                 io_error,
             }
         })?;
@@ -313,7 +312,7 @@ mod tests {
 
         assert!(matches!(
             hm.insert(1, 42, 0),
-            Err(MapError::SyscallError { call, code: -1, io_error }) if call == "bpf_map_update_elem" && io_error.raw_os_error() == Some(EFAULT)
+            Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_update_elem" && io_error.raw_os_error() == Some(EFAULT)
         ));
     }
 
@@ -352,7 +351,7 @@ mod tests {
 
         assert!(matches!(
             hm.remove(&1),
-            Err(MapError::SyscallError { call, code: -1, io_error }) if call == "bpf_map_delete_elem" && io_error.raw_os_error() == Some(EFAULT)
+            Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_delete_elem" && io_error.raw_os_error() == Some(EFAULT)
         ));
     }
 
@@ -390,7 +389,7 @@ mod tests {
 
         assert!(matches!(
             hm.get(&1, 0),
-            Err(MapError::SyscallError { call, code: -1, io_error }) if call == "bpf_map_lookup_elem" && io_error.raw_os_error() == Some(EFAULT)
+            Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_lookup_elem" && io_error.raw_os_error() == Some(EFAULT)
         ));
     }
 
diff --git a/aya/src/maps/hash_map/mod.rs b/aya/src/maps/hash_map/mod.rs
index e878e2d40..60d0ec8a7 100644
--- a/aya/src/maps/hash_map/mod.rs
+++ b/aya/src/maps/hash_map/mod.rs
@@ -29,10 +29,9 @@ pub(crate) fn check_kv_size<K, V>(map: &Map) -> Result<(), MapError> {
 
 pub(crate) fn insert<K, V>(map: &mut Map, key: K, value: V, flags: u64) -> Result<(), MapError> {
     let fd = map.fd_or_err()?;
-    bpf_map_update_elem(fd, Some(&key), &value, flags).map_err(|(code, io_error)| {
+    bpf_map_update_elem(fd, Some(&key), &value, flags).map_err(|(_, io_error)| {
         MapError::SyscallError {
             call: "bpf_map_update_elem".to_owned(),
-            code,
             io_error,
         }
     })?;
@@ -44,9 +43,8 @@ pub(crate) fn remove<K>(map: &mut Map, key: &K) -> Result<(), MapError> {
     let fd = map.fd_or_err()?;
     bpf_map_delete_elem(fd, key)
         .map(|_| ())
-        .map_err(|(code, io_error)| MapError::SyscallError {
+        .map_err(|(_, io_error)| MapError::SyscallError {
             call: "bpf_map_delete_elem".to_owned(),
-            code,
             io_error,
         })
 }
diff --git a/aya/src/maps/hash_map/per_cpu_hash_map.rs b/aya/src/maps/hash_map/per_cpu_hash_map.rs
index 3399254a4..dded84775 100644
--- a/aya/src/maps/hash_map/per_cpu_hash_map.rs
+++ b/aya/src/maps/hash_map/per_cpu_hash_map.rs
@@ -73,10 +73,9 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> {
     /// Returns a slice of values - one for each CPU - associated with the key.
     pub fn get(&self, key: &K, flags: u64) -> Result<PerCpuValues<V>, MapError> {
         let fd = self.inner.deref().fd_or_err()?;
-        let values = bpf_map_lookup_elem_per_cpu(fd, key, flags).map_err(|(code, io_error)| {
+        let values = bpf_map_lookup_elem_per_cpu(fd, key, flags).map_err(|(_, io_error)| {
             MapError::SyscallError {
                 call: "bpf_map_lookup_elem".to_owned(),
-                code,
                 io_error,
             }
         })?;
@@ -127,10 +126,9 @@ impl<T: DerefMut<Target = Map>, K: Pod, V: Pod> PerCpuHashMap<T, K, V> {
     /// ```
     pub fn insert(&mut self, key: K, values: PerCpuValues<V>, flags: u64) -> Result<(), MapError> {
         let fd = self.inner.fd_or_err()?;
-        bpf_map_update_elem_per_cpu(fd, &key, &values, flags).map_err(|(code, io_error)| {
+        bpf_map_update_elem_per_cpu(fd, &key, &values, flags).map_err(|(_, io_error)| {
             MapError::SyscallError {
                 call: "bpf_map_update_elem".to_owned(),
-                code,
                 io_error,
             }
         })?;
diff --git a/aya/src/maps/lpm_trie.rs b/aya/src/maps/lpm_trie.rs
index 405da4629..98c217d74 100644
--- a/aya/src/maps/lpm_trie.rs
+++ b/aya/src/maps/lpm_trie.rs
@@ -129,10 +129,9 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> LpmTrie<T, K, V> {
     /// Returns a copy of the value associated with the longest prefix matching key in the LpmTrie.
     pub fn get(&self, key: &Key<K>, flags: u64) -> Result<V, MapError> {
         let fd = self.inner.deref().fd_or_err()?;
-        let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(code, io_error)| {
+        let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| {
             MapError::SyscallError {
                 call: "bpf_map_lookup_elem".to_owned(),
-                code,
                 io_error,
             }
         })?;
@@ -142,10 +141,9 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> LpmTrie<T, K, V> {
     /// Inserts a key value pair into the map.
     pub fn insert(&self, key: &Key<K>, value: V, flags: u64) -> Result<(), MapError> {
         let fd = self.inner.deref().fd_or_err()?;
-        bpf_map_update_elem(fd, Some(key), &value, flags).map_err(|(code, io_error)| {
+        bpf_map_update_elem(fd, Some(key), &value, flags).map_err(|(_, io_error)| {
             MapError::SyscallError {
                 call: "bpf_map_update_elem".to_owned(),
-                code,
                 io_error,
             }
         })?;
@@ -160,9 +158,8 @@ impl<T: Deref<Target = Map>, K: Pod, V: Pod> LpmTrie<T, K, V> {
         let fd = self.inner.deref().fd_or_err()?;
         bpf_map_delete_elem(fd, key)
             .map(|_| ())
-            .map_err(|(code, io_error)| MapError::SyscallError {
+            .map_err(|(_, io_error)| MapError::SyscallError {
                 call: "bpf_map_delete_elem".to_owned(),
-                code,
                 io_error,
             })
     }
@@ -360,7 +357,7 @@ mod tests {
         let key = Key::new(16, u32::from(ipaddr).to_be());
         assert!(matches!(
             trie.insert(&key, 1, 0),
-            Err(MapError::SyscallError { call, code: -1, io_error }) if call == "bpf_map_update_elem" && io_error.raw_os_error() == Some(EFAULT)
+            Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_update_elem" && io_error.raw_os_error() == Some(EFAULT)
         ));
     }
 
@@ -402,7 +399,7 @@ mod tests {
         let key = Key::new(16, u32::from(ipaddr).to_be());
         assert!(matches!(
             trie.remove(&key),
-            Err(MapError::SyscallError { call, code: -1, io_error }) if call == "bpf_map_delete_elem" && io_error.raw_os_error() == Some(EFAULT)
+            Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_delete_elem" && io_error.raw_os_error() == Some(EFAULT)
         ));
     }
 
@@ -443,7 +440,7 @@ mod tests {
 
         assert!(matches!(
             trie.get(&key, 0),
-            Err(MapError::SyscallError { call, code: -1, io_error }) if call == "bpf_map_lookup_elem" && io_error.raw_os_error() == Some(EFAULT)
+            Err(MapError::SyscallError { call, io_error }) if call == "bpf_map_lookup_elem" && io_error.raw_os_error() == Some(EFAULT)
         ));
     }
 
diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs
index aa45e55e5..af7f489b2 100644
--- a/aya/src/maps/mod.rs
+++ b/aya/src/maps/mod.rs
@@ -50,7 +50,10 @@ use crate::{
     generated::bpf_map_type,
     obj,
     pin::PinError,
-    sys::{bpf_create_map, bpf_get_object, bpf_map_get_next_key, bpf_pin_object, kernel_version},
+    sys::{
+        bpf_create_map, bpf_get_object, bpf_map_get_info_by_fd, bpf_map_get_next_key,
+        bpf_pin_object, kernel_version,
+    },
     util::nr_cpus,
     Pod,
 };
@@ -163,13 +166,10 @@ pub enum MapError {
     ProgramNotLoaded,
 
     /// Syscall failed
-    #[error("the `{call}` syscall failed with code {code}")]
+    #[error("the `{call}` syscall failed")]
     SyscallError {
         /// Syscall Name
         call: String,
-        /// Error code
-        code: libc::c_long,
-        #[source]
         /// Original io::Error
         io_error: io::Error,
     },
@@ -189,10 +189,10 @@ pub enum MapError {
     },
 
     /// Could not pin map by name
-    #[error("map `{name}` requested pinning by name. pinning failed")]
+    #[error("map `{name:?}` requested pinning by name. pinning failed")]
     PinError {
         /// The map name
-        name: String,
+        name: Option<String>,
         /// The reason for the failure
         #[source]
         error: PinError,
@@ -292,18 +292,65 @@ impl Map {
         }
         let map_path = path.as_ref().join(name);
         let path_string = CString::new(map_path.to_str().unwrap()).unwrap();
-        let fd =
-            bpf_get_object(&path_string).map_err(|(code, io_error)| MapError::SyscallError {
-                call: "BPF_OBJ_GET".to_string(),
-                code,
-                io_error,
-            })? as RawFd;
+        let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| MapError::SyscallError {
+            call: "BPF_OBJ_GET".to_string(),
+            io_error,
+        })? as RawFd;
 
         self.fd = Some(fd);
 
         Ok(fd)
     }
 
+    /// Loads a map from a pinned path in bpffs.
+    pub fn from_pinned<P: AsRef<Path>>(path: P) -> Result<Map, MapError> {
+        let path_string =
+            CString::new(path.as_ref().to_string_lossy().into_owned()).map_err(|e| {
+                MapError::PinError {
+                    name: None,
+                    error: PinError::InvalidPinPath {
+                        error: e.to_string(),
+                    },
+                }
+            })?;
+
+        let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| MapError::SyscallError {
+            call: "BPF_OBJ_GET".to_owned(),
+            io_error,
+        })? as RawFd;
+
+        let info = bpf_map_get_info_by_fd(fd).map_err(|io_error| MapError::SyscallError {
+            call: "BPF_MAP_GET_INFO_BY_FD".to_owned(),
+            io_error,
+        })?;
+
+        Ok(Map {
+            obj: obj::parse_map_info(info, crate::PinningType::ByName),
+            fd: Some(fd),
+            btf_fd: None,
+            pinned: true,
+        })
+    }
+
+    /// Loads a map from a [`RawFd`].
+    ///
+    /// If loading from a BPF Filesystem (bpffs) you should use [`Map::from_pinned`].
+    /// This API is intended for cases where you have received a valid BPF FD from some other means.
+    /// For example, you received an FD over Unix Domain Socket.
+    pub fn from_fd(fd: RawFd) -> Result<Map, MapError> {
+        let info = bpf_map_get_info_by_fd(fd).map_err(|io_error| MapError::SyscallError {
+            call: "BPF_OBJ_GET".to_owned(),
+            io_error,
+        })?;
+
+        Ok(Map {
+            obj: obj::parse_map_info(info, crate::PinningType::None),
+            fd: Some(fd),
+            btf_fd: None,
+            pinned: false,
+        })
+    }
+
     /// Returns the [`bpf_map_type`] of this map
     pub fn map_type(&self) -> Result<bpf_map_type, MapError> {
         bpf_map_type::try_from(self.obj.map_type())
@@ -402,11 +449,10 @@ impl<K: Pod> Iterator for MapKeys<'_, K> {
                 self.key = None;
                 None
             }
-            Err((code, io_error)) => {
+            Err((_, io_error)) => {
                 self.err = true;
                 Some(Err(MapError::SyscallError {
                     call: "bpf_map_get_next_key".to_owned(),
-                    code,
                     io_error,
                 }))
             }
diff --git a/aya/src/maps/queue.rs b/aya/src/maps/queue.rs
index 20cb606d2..f53abe578 100644
--- a/aya/src/maps/queue.rs
+++ b/aya/src/maps/queue.rs
@@ -81,9 +81,8 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Queue<T, V> {
         let fd = self.inner.fd_or_err()?;
 
         let value = bpf_map_lookup_and_delete_elem::<u32, _>(fd, None, flags).map_err(
-            |(code, io_error)| MapError::SyscallError {
+            |(_, io_error)| MapError::SyscallError {
                 call: "bpf_map_lookup_and_delete_elem".to_owned(),
-                code,
                 io_error,
             },
         )?;
@@ -97,12 +96,9 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Queue<T, V> {
     /// [`MapError::SyscallError`] if `bpf_map_update_elem` fails.
     pub fn push(&mut self, value: V, flags: u64) -> Result<(), MapError> {
         let fd = self.inner.fd_or_err()?;
-        bpf_map_push_elem(fd, &value, flags).map_err(|(code, io_error)| {
-            MapError::SyscallError {
-                call: "bpf_map_push_elem".to_owned(),
-                code,
-                io_error,
-            }
+        bpf_map_push_elem(fd, &value, flags).map_err(|(_, io_error)| MapError::SyscallError {
+            call: "bpf_map_push_elem".to_owned(),
+            io_error,
         })?;
         Ok(())
     }
diff --git a/aya/src/maps/sock/sock_hash.rs b/aya/src/maps/sock/sock_hash.rs
index 948213b53..a4016ead2 100644
--- a/aya/src/maps/sock/sock_hash.rs
+++ b/aya/src/maps/sock/sock_hash.rs
@@ -87,10 +87,9 @@ impl<T: Deref<Target = Map>, K: Pod> SockHash<T, K> {
     /// Returns the fd of the socket stored at the given key.
     pub fn get(&self, key: &K, flags: u64) -> Result<RawFd, MapError> {
         let fd = self.inner.deref().fd_or_err()?;
-        let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(code, io_error)| {
+        let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| {
             MapError::SyscallError {
                 call: "bpf_map_lookup_elem".to_owned(),
-                code,
                 io_error,
             }
         })?;
diff --git a/aya/src/maps/sock/sock_map.rs b/aya/src/maps/sock/sock_map.rs
index 9941b09e6..1abbf16a5 100644
--- a/aya/src/maps/sock/sock_map.rs
+++ b/aya/src/maps/sock/sock_map.rs
@@ -89,9 +89,8 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>> SockMap<T> {
         let fd = self.inner.fd_or_err()?;
         self.check_bounds(index)?;
         bpf_map_update_elem(fd, Some(&index), &socket.as_raw_fd(), flags).map_err(
-            |(code, io_error)| MapError::SyscallError {
+            |(_, io_error)| MapError::SyscallError {
                 call: "bpf_map_update_elem".to_owned(),
-                code,
                 io_error,
             },
         )?;
@@ -104,9 +103,8 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>> SockMap<T> {
         self.check_bounds(*index)?;
         bpf_map_delete_elem(fd, index)
             .map(|_| ())
-            .map_err(|(code, io_error)| MapError::SyscallError {
+            .map_err(|(_, io_error)| MapError::SyscallError {
                 call: "bpf_map_delete_elem".to_owned(),
-                code,
                 io_error,
             })
     }
diff --git a/aya/src/maps/stack.rs b/aya/src/maps/stack.rs
index 26fe828d3..60d857582 100644
--- a/aya/src/maps/stack.rs
+++ b/aya/src/maps/stack.rs
@@ -81,9 +81,8 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Stack<T, V> {
         let fd = self.inner.fd_or_err()?;
 
         let value = bpf_map_lookup_and_delete_elem::<u32, _>(fd, None, flags).map_err(
-            |(code, io_error)| MapError::SyscallError {
+            |(_, io_error)| MapError::SyscallError {
                 call: "bpf_map_lookup_and_delete_elem".to_owned(),
-                code,
                 io_error,
             },
         )?;
@@ -97,10 +96,9 @@ impl<T: Deref<Target = Map> + DerefMut<Target = Map>, V: Pod> Stack<T, V> {
     /// [`MapError::SyscallError`] if `bpf_map_update_elem` fails.
     pub fn push(&mut self, value: V, flags: u64) -> Result<(), MapError> {
         let fd = self.inner.fd_or_err()?;
-        bpf_map_update_elem(fd, None::<&u32>, &value, flags).map_err(|(code, io_error)| {
+        bpf_map_update_elem(fd, None::<&u32>, &value, flags).map_err(|(_, io_error)| {
             MapError::SyscallError {
                 call: "bpf_map_update_elem".to_owned(),
-                code,
                 io_error,
             }
         })?;
diff --git a/aya/src/maps/stack_trace.rs b/aya/src/maps/stack_trace.rs
index e67584d67..0d73353fb 100644
--- a/aya/src/maps/stack_trace.rs
+++ b/aya/src/maps/stack_trace.rs
@@ -86,7 +86,6 @@ impl<T: Deref<Target = Map>> StackTraceMap<T> {
             sysctl::<usize>("kernel/perf_event_max_stack").map_err(|io_error| {
                 MapError::SyscallError {
                     call: "sysctl".to_owned(),
-                    code: -1,
                     io_error,
                 }
             })?;
@@ -113,9 +112,8 @@ impl<T: Deref<Target = Map>> StackTraceMap<T> {
 
         let mut frames = vec![0; self.max_stack_depth];
         bpf_map_lookup_elem_ptr(fd, Some(stack_id), frames.as_mut_ptr(), flags)
-            .map_err(|(code, io_error)| MapError::SyscallError {
+            .map_err(|(_, io_error)| MapError::SyscallError {
                 call: "bpf_map_lookup_elem".to_owned(),
-                code,
                 io_error,
             })?
             .ok_or(MapError::KeyNotFound)?;
diff --git a/aya/src/obj/mod.rs b/aya/src/obj/mod.rs
index 2d0b39c23..dca36b703 100644
--- a/aya/src/obj/mod.rs
+++ b/aya/src/obj/mod.rs
@@ -19,7 +19,7 @@ use relocation::*;
 
 use crate::{
     bpf_map_def,
-    generated::{bpf_insn, bpf_map_type::BPF_MAP_TYPE_ARRAY, BPF_F_RDONLY_PROG},
+    generated::{bpf_insn, bpf_map_info, bpf_map_type::BPF_MAP_TYPE_ARRAY, BPF_F_RDONLY_PROG},
     obj::btf::{Btf, BtfError, BtfExt, BtfType},
     programs::{CgroupSockAddrAttachType, CgroupSockAttachType, CgroupSockoptAttachType},
     BpfError, BtfMapDef, PinningType,
@@ -1305,6 +1305,45 @@ fn parse_btf_map_def(btf: &Btf, info: &DataSecEntry) -> Result<(String, BtfMapDe
     Ok((map_name.to_string(), map_def))
 }
 
+pub(crate) fn parse_map_info(info: bpf_map_info, pinned: PinningType) -> Map {
+    if info.btf_key_type_id != 0 {
+        Map::Btf(BtfMap {
+            def: BtfMapDef {
+                map_type: info.type_,
+                key_size: info.key_size,
+                value_size: info.value_size,
+                max_entries: info.max_entries,
+                map_flags: info.map_flags,
+                pinning: pinned,
+                btf_key_type_id: info.btf_key_type_id,
+                btf_value_type_id: info.btf_value_type_id,
+            },
+            section_index: 0,
+            symbol_index: 0,
+            data: Vec::new(),
+            // We should never be loading the .bss or .data or .rodata FDs
+            kind: MapKind::Other,
+        })
+    } else {
+        Map::Legacy(LegacyMap {
+            def: bpf_map_def {
+                map_type: info.type_,
+                key_size: info.key_size,
+                value_size: info.value_size,
+                max_entries: info.max_entries,
+                map_flags: info.map_flags,
+                pinning: pinned,
+                id: info.id,
+            },
+            section_index: 0,
+            symbol_index: 0,
+            data: Vec::new(),
+            // We should never be loading the .bss or .data or .rodata FDs
+            kind: MapKind::Other,
+        })
+    }
+}
+
 pub(crate) fn copy_instructions(data: &[u8]) -> Result<Vec<bpf_insn>, ParseError> {
     if data.len() % mem::size_of::<bpf_insn>() > 0 {
         return Err(ParseError::InvalidProgramCode);
diff --git a/aya/src/programs/extension.rs b/aya/src/programs/extension.rs
index f5b5f9dbb..752962443 100644
--- a/aya/src/programs/extension.rs
+++ b/aya/src/programs/extension.rs
@@ -175,7 +175,7 @@ fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramEr
                 let btf_info =
                     sys::btf_obj_get_info_by_fd(btf_fd, &mut buf).map_err(|io_error| {
                         ProgramError::SyscallError {
-                            call: "btf_obj_get_info_by_fd".to_owned(),
+                            call: "bpf_prog_get_info_by_fd".to_owned(),
                             io_error,
                         }
                     })?;
@@ -185,7 +185,7 @@ fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramEr
             }
         }
         Err(io_error) => Err(ProgramError::SyscallError {
-            call: "btf_obj_get_info_by_fd".to_owned(),
+            call: "bpf_prog_get_info_by_fd".to_owned(),
             io_error,
         }),
     }?;
diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs
index 1e0010ea4..f408a49bd 100644
--- a/aya/src/sys/bpf.rs
+++ b/aya/src/sys/bpf.rs
@@ -11,8 +11,8 @@ use libc::{c_char, c_long, close, ENOENT, ENOSPC};
 
 use crate::{
     generated::{
-        bpf_attach_type, bpf_attr, bpf_btf_info, bpf_cmd, bpf_insn, bpf_link_info, bpf_prog_info,
-        bpf_prog_type, BPF_F_REPLACE,
+        bpf_attach_type, bpf_attr, bpf_btf_info, bpf_cmd, bpf_insn, bpf_link_info, bpf_map_info,
+        bpf_prog_info, bpf_prog_type, BPF_F_REPLACE,
     },
     maps::PerCpuValues,
     obj::{
@@ -439,14 +439,29 @@ pub(crate) fn bpf_prog_get_fd_by_id(prog_id: u32) -> Result<RawFd, io::Error> {
 pub(crate) fn bpf_prog_get_info_by_fd(prog_fd: RawFd) -> Result<bpf_prog_info, io::Error> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
     // info gets entirely populated by the kernel
-    let info = unsafe { MaybeUninit::zeroed().assume_init() };
+    let info = MaybeUninit::zeroed();
 
     attr.info.bpf_fd = prog_fd as u32;
     attr.info.info = &info as *const _ as u64;
     attr.info.info_len = mem::size_of::<bpf_prog_info>() as u32;
 
     match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &attr) {
-        Ok(_) => Ok(info),
+        Ok(_) => Ok(unsafe { info.assume_init() }),
+        Err((_, err)) => Err(err),
+    }
+}
+
+pub(crate) fn bpf_map_get_info_by_fd(prog_fd: RawFd) -> Result<bpf_map_info, io::Error> {
+    let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
+    // info gets entirely populated by the kernel
+    let info = MaybeUninit::zeroed();
+
+    attr.info.bpf_fd = prog_fd as u32;
+    attr.info.info = info.as_ptr() as *const _ as u64;
+    attr.info.info_len = mem::size_of::<bpf_map_info>() as u32;
+
+    match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &attr) {
+        Ok(_) => Ok(unsafe { info.assume_init() }),
         Err((_, err)) => Err(err),
     }
 }


Test patch: