Преглед изворни кода

Merge pull request #938 from swananan/enhance_urpobe_symbol_lookup

aya: add symbol lookup in associated debug files
Alessandro Decina пре 10 месеци
родитељ
комит
bde4b5f86b
3 измењених фајлова са 389 додато и 8 уклоњено
  1. 1 1
      aya/Cargo.toml
  2. 264 7
      aya/src/programs/uprobe.rs
  3. 124 0
      xtask/public-api/aya.txt

+ 1 - 1
aya/Cargo.toml

@@ -21,7 +21,7 @@ bytes = { workspace = true }
 lazy_static = { workspace = true }
 libc = { workspace = true }
 log = { workspace = true }
-object = { workspace = true, features = ["elf", "read_core", "std"] }
+object = { workspace = true, features = ["elf", "read_core", "std", "write"] }
 thiserror = { workspace = true }
 tokio = { workspace = true, features = ["rt"], optional = true }
 

+ 264 - 7
aya/src/programs/uprobe.rs

@@ -6,13 +6,13 @@ use std::{
     fs,
     io::{self, BufRead, Cursor, Read},
     mem,
-    os::{fd::AsFd as _, raw::c_char},
+    os::{fd::AsFd as _, raw::c_char, unix::ffi::OsStrExt},
     path::{Path, PathBuf},
     sync::Arc,
 };
 
 use libc::pid_t;
-use object::{Object, ObjectSection, ObjectSymbol};
+use object::{Object, ObjectSection, ObjectSymbol, Symbol};
 use thiserror::Error;
 
 use crate::{
@@ -432,17 +432,103 @@ enum ResolveSymbolError {
 
     #[error("symbol `{0}` in section `{1:?}` which has no offset")]
     SectionFileRangeNone(String, Result<String, object::Error>),
+
+    #[error("failed to access debuglink file `{0}`: `{1}`")]
+    DebuglinkAccessError(String, io::Error),
+
+    #[error("symbol `{0}` not found, mismatched build IDs in main and debug files")]
+    BuildIdMismatch(String),
+}
+
+fn construct_debuglink_path(
+    filename: &[u8],
+    main_path: &Path,
+) -> Result<PathBuf, ResolveSymbolError> {
+    let filename_str = OsStr::from_bytes(filename);
+    let debuglink_path = Path::new(filename_str);
+
+    let resolved_path = if debuglink_path.is_relative() {
+        // If the debug path is relative, resolve it against the parent of the main path
+        main_path.parent().map_or_else(
+            || PathBuf::from(debuglink_path), // Use original if no parent
+            |parent| parent.join(debuglink_path),
+        )
+    } else {
+        // If the path is not relative, just use original
+        PathBuf::from(debuglink_path)
+    };
+
+    Ok(resolved_path)
+}
+
+fn verify_build_ids<'a>(
+    main_obj: &'a object::File<'a>,
+    debug_obj: &'a object::File<'a>,
+    symbol_name: &str,
+) -> Result<(), ResolveSymbolError> {
+    let main_build_id = main_obj.build_id().ok().flatten();
+    let debug_build_id = debug_obj.build_id().ok().flatten();
+
+    match (debug_build_id, main_build_id) {
+        (Some(debug_build_id), Some(main_build_id)) => {
+            // Only perform a comparison if both build IDs are present
+            if debug_build_id != main_build_id {
+                return Err(ResolveSymbolError::BuildIdMismatch(symbol_name.to_owned()));
+            }
+            Ok(())
+        }
+        _ => Ok(()),
+    }
+}
+
+fn find_debug_path_in_object<'a>(
+    obj: &'a object::File<'a>,
+    main_path: &Path,
+    symbol: &str,
+) -> Result<PathBuf, ResolveSymbolError> {
+    match obj.gnu_debuglink() {
+        Ok(Some((filename, _))) => construct_debuglink_path(filename, main_path),
+        Ok(None) => Err(ResolveSymbolError::Unknown(symbol.to_string())),
+        Err(err) => Err(ResolveSymbolError::Object(err)),
+    }
+}
+
+fn find_symbol_in_object<'a>(obj: &'a object::File<'a>, symbol: &str) -> Option<Symbol<'a, 'a>> {
+    obj.dynamic_symbols()
+        .chain(obj.symbols())
+        .find(|sym| sym.name().map(|name| name == symbol).unwrap_or(false))
 }
 
 fn resolve_symbol(path: &Path, symbol: &str) -> Result<u64, ResolveSymbolError> {
     let data = fs::read(path)?;
     let obj = object::read::File::parse(&*data)?;
 
-    let sym = obj
-        .dynamic_symbols()
-        .chain(obj.symbols())
-        .find(|sym| sym.name().map(|name| name == symbol).unwrap_or(false))
-        .ok_or_else(|| ResolveSymbolError::Unknown(symbol.to_string()))?;
+    let mut debug_data = Vec::default();
+    let mut debug_obj_keeper = None;
+
+    let sym = find_symbol_in_object(&obj, symbol).map_or_else(
+        || {
+            // Only search in the debug object if the symbol was not found in the main object
+            let debug_path = find_debug_path_in_object(&obj, path, symbol)?;
+            debug_data = fs::read(&debug_path).map_err(|e| {
+                ResolveSymbolError::DebuglinkAccessError(
+                    debug_path
+                        .to_str()
+                        .unwrap_or("Debuglink path missing")
+                        .to_string(),
+                    e,
+                )
+            })?;
+            let debug_obj = object::read::File::parse(&*debug_data)?;
+
+            verify_build_ids(&obj, &debug_obj, symbol)?;
+
+            debug_obj_keeper = Some(debug_obj);
+            find_symbol_in_object(debug_obj_keeper.as_ref().unwrap(), symbol)
+                .ok_or_else(|| ResolveSymbolError::Unknown(symbol.to_string()))
+        },
+        Ok,
+    )?;
 
     let needs_addr_translation = matches!(
         obj.kind(),
@@ -464,3 +550,174 @@ fn resolve_symbol(path: &Path, symbol: &str) -> Result<u64, ResolveSymbolError>
         Ok(sym.address() - section.address() + offset)
     }
 }
+
+#[cfg(test)]
+mod tests {
+
+    use object::{write::SectionKind, Architecture, BinaryFormat, Endianness};
+
+    use super::*;
+
+    #[test]
+    fn test_relative_path_with_parent() {
+        let filename = b"debug_info";
+        let main_path = Path::new("/usr/lib/main_binary");
+        let expected = Path::new("/usr/lib/debug_info");
+
+        let result = construct_debuglink_path(filename, main_path).unwrap();
+        assert_eq!(
+            result, expected,
+            "The debug path should resolve relative to the main path's parent"
+        );
+    }
+
+    #[test]
+    fn test_relative_path_without_parent() {
+        let filename = b"debug_info";
+        let main_path = Path::new("main_binary");
+        let expected = Path::new("debug_info");
+
+        let result = construct_debuglink_path(filename, main_path).unwrap();
+        assert_eq!(
+            result, expected,
+            "The debug path should be the original path as there is no parent"
+        );
+    }
+
+    #[test]
+    fn test_absolute_path() {
+        let filename = b"/absolute/path/to/debug_info";
+        let main_path = Path::new("/usr/lib/main_binary");
+        let expected = Path::new("/absolute/path/to/debug_info");
+
+        let result = construct_debuglink_path(filename, main_path).unwrap();
+        assert_eq!(
+            result, expected,
+            "The debug path should be the same as the input absolute path"
+        );
+    }
+
+    fn create_elf_with_debuglink(
+        debug_filename: &[u8],
+        crc: u32,
+    ) -> Result<Vec<u8>, object::write::Error> {
+        let mut obj =
+            object::write::Object::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little);
+
+        let section_name = b".gnu_debuglink";
+
+        let section_id = obj.add_section(vec![], section_name.to_vec(), SectionKind::Note);
+
+        let mut debuglink_data = Vec::new();
+
+        debuglink_data.extend_from_slice(debug_filename);
+        debuglink_data.push(0); // Null terminator
+
+        while debuglink_data.len() % 4 != 0 {
+            debuglink_data.push(0);
+        }
+
+        debuglink_data.extend(&crc.to_le_bytes());
+
+        obj.append_section_data(section_id, &debuglink_data, 4 /* align */);
+
+        obj.write()
+    }
+
+    fn create_elf_with_build_id(build_id: &[u8]) -> Result<Vec<u8>, object::write::Error> {
+        let mut obj =
+            object::write::Object::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little);
+
+        let section_name = b".note.gnu.build-id";
+
+        let section_id = obj.add_section(vec![], section_name.to_vec(), SectionKind::Note);
+
+        let mut note_data = Vec::new();
+        let build_id_name = b"GNU";
+
+        note_data.extend(&(build_id_name.len() as u32 + 1).to_le_bytes());
+        note_data.extend(&(build_id.len() as u32).to_le_bytes());
+        note_data.extend(&3u32.to_le_bytes());
+
+        note_data.extend_from_slice(build_id_name);
+        note_data.push(0); // Null terminator
+        note_data.extend_from_slice(build_id);
+
+        obj.append_section_data(section_id, &note_data, 4 /* align */);
+
+        obj.write()
+    }
+
+    fn aligned_slice(vec: &mut Vec<u8>) -> &mut [u8] {
+        let alignment = 8;
+
+        let original_size = vec.len();
+        let total_size = original_size + alignment - 1;
+
+        if vec.capacity() < total_size {
+            vec.reserve(total_size - vec.capacity());
+        }
+
+        if vec.len() < total_size {
+            vec.resize(total_size, 0);
+        }
+
+        let ptr = vec.as_ptr() as usize;
+
+        let aligned_ptr = (ptr + alignment - 1) & !(alignment - 1);
+
+        let offset = aligned_ptr - ptr;
+
+        if offset > 0 {
+            let tmp = vec.len();
+            vec.copy_within(0..tmp - offset, offset);
+        }
+
+        &mut vec[offset..offset + original_size]
+    }
+
+    #[test]
+    fn test_find_debug_path_success() {
+        let debug_filepath = b"main.debug";
+        let mut main_bytes = create_elf_with_debuglink(debug_filepath, 0x123 /* fake CRC */)
+            .expect("got main_bytes");
+        let align_bytes = aligned_slice(&mut main_bytes);
+        let main_obj = object::File::parse(&*align_bytes).expect("got main obj");
+
+        let main_path = Path::new("/path/to/main");
+        let result = find_debug_path_in_object(&main_obj, main_path, "symbol");
+
+        assert_eq!(result.unwrap(), Path::new("/path/to/main.debug"));
+    }
+
+    #[test]
+    fn test_verify_build_ids_same() {
+        let build_id = b"test_build_id";
+        let mut main_bytes = create_elf_with_build_id(build_id).expect("got main_bytes");
+        let align_bytes = aligned_slice(&mut main_bytes);
+        let main_obj = object::File::parse(&*align_bytes).expect("got main obj");
+        let debug_build_id = b"test_build_id";
+        let mut debug_bytes = create_elf_with_build_id(debug_build_id).expect("got debug bytes");
+        let align_bytes = aligned_slice(&mut debug_bytes);
+        let debug_obj = object::File::parse(&*align_bytes).expect("got debug obj");
+
+        assert!(verify_build_ids(&main_obj, &debug_obj, "symbol_name").is_ok());
+    }
+
+    #[test]
+    fn test_verify_build_ids_different() {
+        let build_id = b"main_build_id";
+        let mut main_bytes = create_elf_with_build_id(build_id).expect("got main_bytes");
+        let align_bytes = aligned_slice(&mut main_bytes);
+        let main_obj = object::File::parse(&*align_bytes).expect("got main obj");
+        let debug_build_id = b"debug_build_id";
+        let mut debug_bytes = create_elf_with_build_id(debug_build_id).expect("got debug bytes");
+        let align_bytes = aligned_slice(&mut debug_bytes);
+        let debug_obj = object::File::parse(&*align_bytes).expect("got debug obj");
+
+        assert!(matches!(
+            verify_build_ids(&main_obj, &debug_obj, "symbol_name"),
+            Err(ResolveSymbolError::BuildIdMismatch(_))
+        ));
+    }
+}

+ 124 - 0
xtask/public-api/aya.txt

@@ -469,6 +469,10 @@ impl core::marker::Sync for aya::maps::perf::Events
 impl core::marker::Unpin for aya::maps::perf::Events
 impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::perf::Events
 impl core::panic::unwind_safe::UnwindSafe for aya::maps::perf::Events
+impl<Q, K> equivalent::Equivalent<K> for aya::maps::perf::Events where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::maps::perf::Events::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::maps::perf::Events where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::maps::perf::Events::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::maps::perf::Events where U: core::convert::From<T>
 pub fn aya::maps::perf::Events::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::maps::perf::Events where U: core::convert::Into<T>
@@ -2531,6 +2535,10 @@ impl core::marker::Sync for aya::programs::cgroup_device::CgroupDeviceLinkId
 impl core::marker::Unpin for aya::programs::cgroup_device::CgroupDeviceLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::cgroup_device::CgroupDeviceLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::cgroup_device::CgroupDeviceLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::cgroup_device::CgroupDeviceLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::cgroup_device::CgroupDeviceLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::cgroup_device::CgroupDeviceLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::cgroup_device::CgroupDeviceLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::cgroup_device::CgroupDeviceLinkId where U: core::convert::From<T>
 pub fn aya::programs::cgroup_device::CgroupDeviceLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::cgroup_device::CgroupDeviceLinkId where U: core::convert::Into<T>
@@ -2677,6 +2685,10 @@ impl core::marker::Sync for aya::programs::cgroup_skb::CgroupSkbLinkId
 impl core::marker::Unpin for aya::programs::cgroup_skb::CgroupSkbLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::cgroup_skb::CgroupSkbLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::cgroup_skb::CgroupSkbLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::cgroup_skb::CgroupSkbLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::cgroup_skb::CgroupSkbLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::cgroup_skb::CgroupSkbLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::cgroup_skb::CgroupSkbLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::cgroup_skb::CgroupSkbLinkId where U: core::convert::From<T>
 pub fn aya::programs::cgroup_skb::CgroupSkbLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::cgroup_skb::CgroupSkbLinkId where U: core::convert::Into<T>
@@ -2789,6 +2801,10 @@ impl core::marker::Sync for aya::programs::cgroup_sock::CgroupSockLinkId
 impl core::marker::Unpin for aya::programs::cgroup_sock::CgroupSockLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::cgroup_sock::CgroupSockLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::cgroup_sock::CgroupSockLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::cgroup_sock::CgroupSockLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::cgroup_sock::CgroupSockLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::cgroup_sock::CgroupSockLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::cgroup_sock::CgroupSockLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::cgroup_sock::CgroupSockLinkId where U: core::convert::From<T>
 pub fn aya::programs::cgroup_sock::CgroupSockLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::cgroup_sock::CgroupSockLinkId where U: core::convert::Into<T>
@@ -2901,6 +2917,10 @@ impl core::marker::Sync for aya::programs::cgroup_sock_addr::CgroupSockAddrLinkI
 impl core::marker::Unpin for aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId where U: core::convert::From<T>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId where U: core::convert::Into<T>
@@ -3013,6 +3033,10 @@ impl core::marker::Sync for aya::programs::cgroup_sockopt::CgroupSockoptLinkId
 impl core::marker::Unpin for aya::programs::cgroup_sockopt::CgroupSockoptLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::cgroup_sockopt::CgroupSockoptLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::cgroup_sockopt::CgroupSockoptLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::cgroup_sockopt::CgroupSockoptLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::cgroup_sockopt::CgroupSockoptLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::cgroup_sockopt::CgroupSockoptLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::cgroup_sockopt::CgroupSockoptLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::cgroup_sockopt::CgroupSockoptLinkId where U: core::convert::From<T>
 pub fn aya::programs::cgroup_sockopt::CgroupSockoptLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::cgroup_sockopt::CgroupSockoptLinkId where U: core::convert::Into<T>
@@ -3125,6 +3149,10 @@ impl core::marker::Sync for aya::programs::cgroup_sysctl::CgroupSysctlLinkId
 impl core::marker::Unpin for aya::programs::cgroup_sysctl::CgroupSysctlLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::cgroup_sysctl::CgroupSysctlLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::cgroup_sysctl::CgroupSysctlLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::cgroup_sysctl::CgroupSysctlLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::cgroup_sysctl::CgroupSysctlLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::cgroup_sysctl::CgroupSysctlLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::cgroup_sysctl::CgroupSysctlLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::cgroup_sysctl::CgroupSysctlLinkId where U: core::convert::From<T>
 pub fn aya::programs::cgroup_sysctl::CgroupSysctlLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::cgroup_sysctl::CgroupSysctlLinkId where U: core::convert::Into<T>
@@ -3275,6 +3303,10 @@ impl core::marker::Sync for aya::programs::extension::ExtensionLinkId
 impl core::marker::Unpin for aya::programs::extension::ExtensionLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::extension::ExtensionLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::extension::ExtensionLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::extension::ExtensionLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::extension::ExtensionLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::extension::ExtensionLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::extension::ExtensionLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::extension::ExtensionLinkId where U: core::convert::From<T>
 pub fn aya::programs::extension::ExtensionLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::extension::ExtensionLinkId where U: core::convert::Into<T>
@@ -3391,6 +3423,10 @@ impl core::marker::Sync for aya::programs::fentry::FEntryLinkId
 impl core::marker::Unpin for aya::programs::fentry::FEntryLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::fentry::FEntryLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::fentry::FEntryLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::fentry::FEntryLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::fentry::FEntryLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::fentry::FEntryLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::fentry::FEntryLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::fentry::FEntryLinkId where U: core::convert::From<T>
 pub fn aya::programs::fentry::FEntryLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::fentry::FEntryLinkId where U: core::convert::Into<T>
@@ -3507,6 +3543,10 @@ impl core::marker::Sync for aya::programs::fexit::FExitLinkId
 impl core::marker::Unpin for aya::programs::fexit::FExitLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::fexit::FExitLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::fexit::FExitLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::fexit::FExitLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::fexit::FExitLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::fexit::FExitLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::fexit::FExitLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::fexit::FExitLinkId where U: core::convert::From<T>
 pub fn aya::programs::fexit::FExitLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::fexit::FExitLinkId where U: core::convert::Into<T>
@@ -3661,6 +3701,10 @@ impl core::marker::Sync for aya::programs::kprobe::KProbeLinkId
 impl core::marker::Unpin for aya::programs::kprobe::KProbeLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::kprobe::KProbeLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::kprobe::KProbeLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::kprobe::KProbeLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::kprobe::KProbeLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::kprobe::KProbeLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::kprobe::KProbeLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::kprobe::KProbeLinkId where U: core::convert::From<T>
 pub fn aya::programs::kprobe::KProbeLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::kprobe::KProbeLinkId where U: core::convert::Into<T>
@@ -3817,6 +3861,10 @@ impl core::marker::Sync for aya::programs::links::FdLinkId
 impl core::marker::Unpin for aya::programs::links::FdLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::links::FdLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::links::FdLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::links::FdLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::links::FdLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::links::FdLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::links::FdLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::links::FdLinkId where U: core::convert::From<T>
 pub fn aya::programs::links::FdLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::links::FdLinkId where U: core::convert::Into<T>
@@ -3919,6 +3967,10 @@ impl core::marker::Sync for aya::programs::links::ProgAttachLinkId
 impl core::marker::Unpin for aya::programs::links::ProgAttachLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::links::ProgAttachLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::links::ProgAttachLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::links::ProgAttachLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::links::ProgAttachLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::links::ProgAttachLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::links::ProgAttachLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::links::ProgAttachLinkId where U: core::convert::From<T>
 pub fn aya::programs::links::ProgAttachLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::links::ProgAttachLinkId where U: core::convert::Into<T>
@@ -4094,6 +4146,10 @@ impl core::marker::Sync for aya::programs::lirc_mode2::LircLinkId
 impl core::marker::Unpin for aya::programs::lirc_mode2::LircLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::lirc_mode2::LircLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::lirc_mode2::LircLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::lirc_mode2::LircLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::lirc_mode2::LircLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::lirc_mode2::LircLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::lirc_mode2::LircLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::lirc_mode2::LircLinkId where U: core::convert::From<T>
 pub fn aya::programs::lirc_mode2::LircLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::lirc_mode2::LircLinkId where U: core::convert::Into<T>
@@ -4260,6 +4316,10 @@ impl core::marker::Sync for aya::programs::lsm::LsmLinkId
 impl core::marker::Unpin for aya::programs::lsm::LsmLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::lsm::LsmLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::lsm::LsmLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::lsm::LsmLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::lsm::LsmLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::lsm::LsmLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::lsm::LsmLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::lsm::LsmLinkId where U: core::convert::From<T>
 pub fn aya::programs::lsm::LsmLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::lsm::LsmLinkId where U: core::convert::Into<T>
@@ -4321,6 +4381,10 @@ impl core::marker::Sync for aya::programs::perf_attach::PerfLinkId
 impl core::marker::Unpin for aya::programs::perf_attach::PerfLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::perf_attach::PerfLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::perf_attach::PerfLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::perf_attach::PerfLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::perf_attach::PerfLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::perf_attach::PerfLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::perf_attach::PerfLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::perf_attach::PerfLinkId where U: core::convert::From<T>
 pub fn aya::programs::perf_attach::PerfLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::perf_attach::PerfLinkId where U: core::convert::Into<T>
@@ -4555,6 +4619,10 @@ impl core::marker::Sync for aya::programs::perf_event::PerfEventLinkId
 impl core::marker::Unpin for aya::programs::perf_event::PerfEventLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::perf_event::PerfEventLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::perf_event::PerfEventLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::perf_event::PerfEventLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::perf_event::PerfEventLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::perf_event::PerfEventLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::perf_event::PerfEventLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::perf_event::PerfEventLinkId where U: core::convert::From<T>
 pub fn aya::programs::perf_event::PerfEventLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::perf_event::PerfEventLinkId where U: core::convert::Into<T>
@@ -4671,6 +4739,10 @@ impl core::marker::Sync for aya::programs::raw_trace_point::RawTracePointLinkId
 impl core::marker::Unpin for aya::programs::raw_trace_point::RawTracePointLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::raw_trace_point::RawTracePointLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::raw_trace_point::RawTracePointLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::raw_trace_point::RawTracePointLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::raw_trace_point::RawTracePointLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::raw_trace_point::RawTracePointLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::raw_trace_point::RawTracePointLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::raw_trace_point::RawTracePointLinkId where U: core::convert::From<T>
 pub fn aya::programs::raw_trace_point::RawTracePointLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::raw_trace_point::RawTracePointLinkId where U: core::convert::Into<T>
@@ -4787,6 +4859,10 @@ impl core::marker::Sync for aya::programs::sk_lookup::SkLookupLinkId
 impl core::marker::Unpin for aya::programs::sk_lookup::SkLookupLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::sk_lookup::SkLookupLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::sk_lookup::SkLookupLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::sk_lookup::SkLookupLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::sk_lookup::SkLookupLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::sk_lookup::SkLookupLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::sk_lookup::SkLookupLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::sk_lookup::SkLookupLinkId where U: core::convert::From<T>
 pub fn aya::programs::sk_lookup::SkLookupLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::sk_lookup::SkLookupLinkId where U: core::convert::Into<T>
@@ -4903,6 +4979,10 @@ impl core::marker::Sync for aya::programs::sk_msg::SkMsgLinkId
 impl core::marker::Unpin for aya::programs::sk_msg::SkMsgLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::sk_msg::SkMsgLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::sk_msg::SkMsgLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::sk_msg::SkMsgLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::sk_msg::SkMsgLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::sk_msg::SkMsgLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::sk_msg::SkMsgLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::sk_msg::SkMsgLinkId where U: core::convert::From<T>
 pub fn aya::programs::sk_msg::SkMsgLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::sk_msg::SkMsgLinkId where U: core::convert::Into<T>
@@ -5052,6 +5132,10 @@ impl core::marker::Sync for aya::programs::sk_skb::SkSkbLinkId
 impl core::marker::Unpin for aya::programs::sk_skb::SkSkbLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::sk_skb::SkSkbLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::sk_skb::SkSkbLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::sk_skb::SkSkbLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::sk_skb::SkSkbLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::sk_skb::SkSkbLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::sk_skb::SkSkbLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::sk_skb::SkSkbLinkId where U: core::convert::From<T>
 pub fn aya::programs::sk_skb::SkSkbLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::sk_skb::SkSkbLinkId where U: core::convert::Into<T>
@@ -5168,6 +5252,10 @@ impl core::marker::Sync for aya::programs::sock_ops::SockOpsLinkId
 impl core::marker::Unpin for aya::programs::sock_ops::SockOpsLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::sock_ops::SockOpsLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::sock_ops::SockOpsLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::sock_ops::SockOpsLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::sock_ops::SockOpsLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::sock_ops::SockOpsLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::sock_ops::SockOpsLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::sock_ops::SockOpsLinkId where U: core::convert::From<T>
 pub fn aya::programs::sock_ops::SockOpsLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::sock_ops::SockOpsLinkId where U: core::convert::Into<T>
@@ -5313,6 +5401,10 @@ impl core::marker::Sync for aya::programs::socket_filter::SocketFilterLinkId
 impl core::marker::Unpin for aya::programs::socket_filter::SocketFilterLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::socket_filter::SocketFilterLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::socket_filter::SocketFilterLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::socket_filter::SocketFilterLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::socket_filter::SocketFilterLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::socket_filter::SocketFilterLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::socket_filter::SocketFilterLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::socket_filter::SocketFilterLinkId where U: core::convert::From<T>
 pub fn aya::programs::socket_filter::SocketFilterLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::socket_filter::SocketFilterLinkId where U: core::convert::Into<T>
@@ -5351,6 +5443,10 @@ impl core::marker::Sync for aya::programs::tc::TcAttachType
 impl core::marker::Unpin for aya::programs::tc::TcAttachType
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::TcAttachType
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::tc::TcAttachType
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::tc::TcAttachType where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::tc::TcAttachType::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::tc::TcAttachType where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::tc::TcAttachType::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::tc::TcAttachType where U: core::convert::From<T>
 pub fn aya::programs::tc::TcAttachType::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::tc::TcAttachType where U: core::convert::Into<T>
@@ -5508,6 +5604,10 @@ impl core::marker::Sync for aya::programs::tc::SchedClassifierLinkId
 impl core::marker::Unpin for aya::programs::tc::SchedClassifierLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::SchedClassifierLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::tc::SchedClassifierLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::tc::SchedClassifierLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::tc::SchedClassifierLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::tc::SchedClassifierLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::tc::SchedClassifierLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::tc::SchedClassifierLinkId where U: core::convert::From<T>
 pub fn aya::programs::tc::SchedClassifierLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::tc::SchedClassifierLinkId where U: core::convert::Into<T>
@@ -5653,6 +5753,10 @@ impl core::marker::Sync for aya::programs::tp_btf::BtfTracePointLinkId
 impl core::marker::Unpin for aya::programs::tp_btf::BtfTracePointLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::tp_btf::BtfTracePointLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::tp_btf::BtfTracePointLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::tp_btf::BtfTracePointLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::tp_btf::BtfTracePointLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::tp_btf::BtfTracePointLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::tp_btf::BtfTracePointLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::tp_btf::BtfTracePointLinkId where U: core::convert::From<T>
 pub fn aya::programs::tp_btf::BtfTracePointLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::tp_btf::BtfTracePointLinkId where U: core::convert::Into<T>
@@ -5807,6 +5911,10 @@ impl core::marker::Sync for aya::programs::trace_point::TracePointLinkId
 impl core::marker::Unpin for aya::programs::trace_point::TracePointLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::trace_point::TracePointLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::trace_point::TracePointLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::trace_point::TracePointLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::trace_point::TracePointLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::trace_point::TracePointLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::trace_point::TracePointLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::trace_point::TracePointLinkId where U: core::convert::From<T>
 pub fn aya::programs::trace_point::TracePointLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::trace_point::TracePointLinkId where U: core::convert::Into<T>
@@ -5968,6 +6076,10 @@ impl core::marker::Sync for aya::programs::uprobe::UProbeLinkId
 impl core::marker::Unpin for aya::programs::uprobe::UProbeLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::uprobe::UProbeLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::uprobe::UProbeLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::uprobe::UProbeLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::uprobe::UProbeLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::uprobe::UProbeLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::uprobe::UProbeLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::uprobe::UProbeLinkId where U: core::convert::From<T>
 pub fn aya::programs::uprobe::UProbeLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::uprobe::UProbeLinkId where U: core::convert::Into<T>
@@ -6233,6 +6345,10 @@ impl core::marker::Sync for aya::programs::xdp::XdpLinkId
 impl core::marker::Unpin for aya::programs::xdp::XdpLinkId
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::xdp::XdpLinkId
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::xdp::XdpLinkId
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::xdp::XdpLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::xdp::XdpLinkId::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::xdp::XdpLinkId where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::xdp::XdpLinkId::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::xdp::XdpLinkId where U: core::convert::From<T>
 pub fn aya::programs::xdp::XdpLinkId::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::xdp::XdpLinkId where U: core::convert::Into<T>
@@ -6864,6 +6980,10 @@ impl core::marker::Sync for aya::programs::tc::TcAttachType
 impl core::marker::Unpin for aya::programs::tc::TcAttachType
 impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::TcAttachType
 impl core::panic::unwind_safe::UnwindSafe for aya::programs::tc::TcAttachType
+impl<Q, K> equivalent::Equivalent<K> for aya::programs::tc::TcAttachType where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::tc::TcAttachType::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::programs::tc::TcAttachType where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::programs::tc::TcAttachType::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::programs::tc::TcAttachType where U: core::convert::From<T>
 pub fn aya::programs::tc::TcAttachType::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::programs::tc::TcAttachType where U: core::convert::Into<T>
@@ -8528,6 +8648,10 @@ impl core::marker::Sync for aya::util::KernelVersion
 impl core::marker::Unpin for aya::util::KernelVersion
 impl core::panic::unwind_safe::RefUnwindSafe for aya::util::KernelVersion
 impl core::panic::unwind_safe::UnwindSafe for aya::util::KernelVersion
+impl<Q, K> equivalent::Equivalent<K> for aya::util::KernelVersion where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::util::KernelVersion::equivalent(&self, key: &K) -> bool
+impl<Q, K> hashbrown::Equivalent<K> for aya::util::KernelVersion where Q: core::cmp::Eq + core::marker::Sized, K: core::borrow::Borrow<Q> + core::marker::Sized
+pub fn aya::util::KernelVersion::equivalent(&self, key: &K) -> bool
 impl<T, U> core::convert::Into<U> for aya::util::KernelVersion where U: core::convert::From<T>
 pub fn aya::util::KernelVersion::into(self) -> U
 impl<T, U> core::convert::TryFrom<U> for aya::util::KernelVersion where U: core::convert::Into<T>