diff --git a/Cargo.toml b/Cargo.toml
old mode 100755
new mode 100644
diff --git a/crates/examples/src/readobj/macho.rs b/crates/examples/src/readobj/macho.rs
index 456b77ea..11672427 100644
--- a/crates/examples/src/readobj/macho.rs
+++ b/crates/examples/src/readobj/macho.rs
@@ -9,7 +9,7 @@ pub(super) fn print_dyld_cache(p: &mut Printer<'_>, data: &[u8]) {
             print_dyld_cache_header(p, endian, header);
             let mappings = header.mappings(endian, data).print_err(p);
             if let Some(mappings) = mappings {
-                print_dyld_cache_mappings(p, endian, mappings);
+                print_dyld_cache_mappings(p, mappings);
             }
             if let Some(images) = header.images(endian, data).print_err(p) {
                 print_dyld_cache_images(p, endian, data, mappings, images);
@@ -36,24 +36,60 @@ pub(super) fn print_dyld_cache_header(
     });
 }
 
-pub(super) fn print_dyld_cache_mappings(
-    p: &mut Printer<'_>,
-    endian: Endianness,
-    mappings: &[DyldCacheMappingInfo<Endianness>],
-) {
+pub(super) fn print_dyld_cache_mappings(p: &mut Printer<'_>, mappings: DyldCacheMappingSlice) {
     if !p.options.file {
         return;
     }
-    for mapping in mappings {
-        p.group("DyldCacheMappingInfo", |p| {
-            p.field_hex("Address", mapping.address.get(endian));
-            p.field_hex("Size", mapping.size.get(endian));
-            p.field_hex("FileOffset", mapping.file_offset.get(endian));
-            p.field_hex("MaxProt", mapping.max_prot.get(endian));
-            p.flags(mapping.max_prot.get(endian), 0, FLAGS_VM);
-            p.field_hex("InitProt", mapping.init_prot.get(endian));
-            p.flags(mapping.init_prot.get(endian), 0, FLAGS_VM);
-        });
+
+    match mappings {
+        DyldCacheMappingSlice::V1 {
+            endian,
+            data: _,
+            info,
+        } => {
+            for mapping in info.iter() {
+                p.group("DyldCacheMappingInfo", |p| {
+                    p.field_hex("Address", mapping.address.get(endian));
+                    p.field_hex("Size", mapping.size.get(endian));
+                    p.field_hex("FileOffset", mapping.file_offset.get(endian));
+                    p.field_hex("MaxProt", mapping.max_prot.get(endian));
+                    p.flags(mapping.max_prot.get(endian), 0, FLAGS_VM);
+                    p.field_hex("InitProt", mapping.init_prot.get(endian));
+                    p.flags(mapping.init_prot.get(endian), 0, FLAGS_VM);
+                });
+            }
+        }
+        DyldCacheMappingSlice::V2 {
+            endian,
+            data: _,
+            info,
+        } => {
+            for mapping in info.iter() {
+                p.group("DyldCacheMappingAndSlideInfo", |p| {
+                    p.field_hex("Address", mapping.address.get(endian));
+                    p.field_hex("Size", mapping.size.get(endian));
+                    p.field_hex("FileOffset", mapping.file_offset.get(endian));
+                    p.field_hex(
+                        "SlideInfoFileOffset",
+                        mapping.slide_info_file_offset.get(endian),
+                    );
+                    p.field_hex(
+                        "SlideInfoFileSize",
+                        mapping.slide_info_file_size.get(endian),
+                    );
+                    p.field_hex("Flags", mapping.flags.get(endian));
+                    p.flags(mapping.flags.get(endian), 0, FLAGS_DYLD_CACHE_MAPPING);
+                    p.field_hex("MaxProt", mapping.max_prot.get(endian));
+                    p.flags(mapping.max_prot.get(endian), 0, FLAGS_VM);
+                    p.field_hex("InitProt", mapping.init_prot.get(endian));
+                    p.flags(mapping.init_prot.get(endian), 0, FLAGS_VM);
+                });
+            }
+        }
+        _ => panic!(
+            "If this case is hit, it means that someone added a variant to the (non-exhaustive) \
+            DyldCacheMappingSlice enum and forgot to update this example"
+        ),
     }
 }
 
@@ -61,7 +97,7 @@ pub(super) fn print_dyld_cache_images(
     p: &mut Printer<'_>,
     endian: Endianness,
     data: &[u8],
-    mappings: Option<&[DyldCacheMappingInfo<Endianness>]>,
+    mappings: Option<DyldCacheMappingSlice>,
     images: &[DyldCacheImageInfo<Endianness>],
 ) {
     for image in images {
@@ -78,8 +114,9 @@ pub(super) fn print_dyld_cache_images(
                 p.field_hex("Pad", image.pad.get(endian));
             });
         }
-        if let Some(offset) =
-            mappings.and_then(|mappings| image.file_offset(endian, mappings).print_err(p))
+        if let Some(offset) = mappings
+            .as_ref()
+            .and_then(|mappings| image.file_offset(endian, mappings).print_err(p))
         {
             if p.options.file {
                 p.blank();
@@ -931,6 +968,13 @@ const FLAGS_CPU_SUBTYPE_ARM64: &[Flag<u32>] = &flags!(
 );
 const FLAGS_CPU_SUBTYPE_ARM64_32: &[Flag<u32>] =
     &flags!(CPU_SUBTYPE_ARM64_32_ALL, CPU_SUBTYPE_ARM64_32_V8);
+const FLAGS_DYLD_CACHE_MAPPING: &[Flag<u64>] = &flags!(
+    DYLD_CACHE_MAPPING_AUTH_DATA,
+    DYLD_CACHE_MAPPING_DIRTY_DATA,
+    DYLD_CACHE_MAPPING_CONST_DATA,
+    DYLD_CACHE_MAPPING_TEXT_STUBS,
+    DYLD_CACHE_DYNAMIC_CONFIG_DATA,
+);
 const FLAGS_MH_FILETYPE: &[Flag<u32>] = &flags!(
     MH_OBJECT,
     MH_EXECUTE,
diff --git a/src/macho.rs b/src/macho.rs
index 88919d62..1c6032db 100644
--- a/src/macho.rs
+++ b/src/macho.rs
@@ -9,6 +9,7 @@
 
 use crate::endian::{BigEndian, Endian, U64Bytes, U16, U32, U64};
 use crate::pod::Pod;
+use core::fmt::{self, Debug};
 
 // Definitions from "/usr/include/mach/machine.h".
 
@@ -282,6 +283,39 @@ pub const VM_PROT_WRITE: u32 = 0x02;
 /// execute permission
 pub const VM_PROT_EXECUTE: u32 = 0x04;
 
+// Definitions from ptrauth.h
+
+/// ptrauth_key enum
+#[repr(u8)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum PtrauthKey {
+    /// ptrauth_key_asia
+    IA = 0,
+    /// ptrauth_key_asib
+    IB = 1,
+    /// ptrauth_key_asda
+    DA = 2,
+    /// ptrauth_key_asdb
+    DB = 3,
+}
+
+/// Pointer auth data
+pub struct Ptrauth {
+    pub key: PtrauthKey,
+    pub diversity: u16,
+    pub addr_div: bool,
+}
+
+impl Debug for Ptrauth {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Ptrauth")
+            .field("key", &self.key)
+            .field("diversity", &format_args!("{:#x}", self.diversity))
+            .field("addr_div", &self.addr_div)
+            .finish()
+    }
+}
+
 // Definitions from https://opensource.apple.com/source/dyld/dyld-210.2.3/launch-cache/dyld_cache_format.h.auto.html
 
 /// The dyld cache header.
@@ -296,44 +330,142 @@ pub struct DyldCacheHeader<E: Endian> {
     /// e.g. "dyld_v0    i386"
     pub magic: [u8; 16],
     /// file offset to first dyld_cache_mapping_info
-    pub mapping_offset: U32<E>, // offset: 0x10
+    pub mapping_offset: U32<E>,
     /// number of dyld_cache_mapping_info entries
-    pub mapping_count: U32<E>, // offset: 0x14
-    /// file offset to first dyld_cache_image_info
-    pub images_offset: U32<E>, // offset: 0x18
-    /// number of dyld_cache_image_info entries
-    pub images_count: U32<E>, // offset: 0x1c
+    pub mapping_count: U32<E>,
+    /// UNUSED: moved to imagesOffset to prevent older dsc_extarctors from crashing
+    pub images_offset_old: U32<E>,
+    /// UNUSED: moved to imagesCount to prevent older dsc_extarctors from crashing
+    pub images_count_old: U32<E>,
     /// base address of dyld when cache was built
-    pub dyld_base_address: U64<E>, // offset: 0x20
-    reserved1: [u8; 32], // offset: 0x28
+    pub dyld_base_address: U64<E>,
+    /// file offset of code signature blob
+    pub code_signature_offset: U64<E>,
+    /// size of code signature blob (zero means to end of file)
+    pub code_signature_size: U64<E>,
+    /// unused.  Used to be file offset of kernel slid info
+    pub slide_info_offset_unused: U64<E>,
+    /// unused.  Used to be size of kernel slid info
+    pub slide_info_size_unused: U64<E>,
     /// file offset of where local symbols are stored
-    pub local_symbols_offset: U64<E>, // offset: 0x48
+    pub local_symbols_offset: U64<E>,
     /// size of local symbols information
-    pub local_symbols_size: U64<E>, // offset: 0x50
+    pub local_symbols_size: U64<E>,
     /// unique value for each shared cache file
-    pub uuid: [u8; 16], // offset: 0x58
-    reserved2: [u8; 32], // offset: 0x68
-    reserved3: [u8; 32], // offset: 0x88
-    reserved4: [u8; 32], // offset: 0xa8
-    reserved5: [u8; 32], // offset: 0xc8
-    reserved6: [u8; 32], // offset: 0xe8
-    reserved7: [u8; 32], // offset: 0x108
-    reserved8: [u8; 32], // offset: 0x128
-    reserved9: [u8; 32], // offset: 0x148
-    reserved10: [u8; 32], // offset: 0x168
-    /// file offset to first dyld_subcache_info
-    pub subcaches_offset: U32<E>, // offset: 0x188
-    /// number of dyld_subcache_info entries
-    pub subcaches_count: U32<E>, // offset: 0x18c
-    /// the UUID of the .symbols subcache
-    pub symbols_subcache_uuid: [u8; 16], // offset: 0x190
-    reserved11: [u8; 32], // offset: 0x1a0
+    pub uuid: [u8; 16],
+    /// 0 for development, 1 for production, 2 for multi-cache
+    pub cache_type: U64<E>,
+    /// file offset to table of uint64_t pool addresses
+    pub branch_pools_offset: U32<E>,
+    /// number of uint64_t entries
+    pub branch_pools_count: U32<E>,
+    /// (unslid) address of mach_header of dyld in cache
+    pub dyld_in_cache_mh: U64<E>,
+    /// (unslid) address of entry point (_dyld_start) of dyld in cache
+    pub dyld_in_cache_entry: U64<E>,
+    /// file offset to first dyld_cache_image_text_info
+    pub images_text_offset: U64<E>,
+    /// number of dyld_cache_image_text_info entries
+    pub images_text_count: U64<E>,
+    /// (unslid) address of dyld_cache_patch_info
+    pub patch_info_addr: U64<E>,
+    /// Size of all of the patch information pointed to via the dyld_cache_patch_info
+    pub patch_info_size: U64<E>,
+    /// unused
+    pub other_image_group_addr_unused: U64<E>,
+    /// unused
+    pub other_image_group_size_unused: U64<E>,
+    /// (unslid) address of list of program launch closures
+    pub prog_closures_addr: U64<E>,
+    /// size of list of program launch closures
+    pub prog_closures_size: U64<E>,
+    /// (unslid) address of trie of indexes into program launch closures
+    pub prog_closures_trie_addr: U64<E>,
+    /// size of trie of indexes into program launch closures
+    pub prog_closures_trie_size: U64<E>,
+    /// platform number (macOS=1, etc)
+    pub platform: U32<E>,
+    // bitfield of values
+    pub flags: U32<E>,
+    /// base load address of cache if not slid
+    pub shared_region_start: U64<E>,
+    /// overall size required to map the cache and all subCaches, if any
+    pub shared_region_size: U64<E>,
+    /// runtime slide of cache can be between zero and this value
+    pub max_slide: U64<E>,
+    /// (unslid) address of ImageArray for dylibs in this cache
+    pub dylibs_image_array_addr: U64<E>,
+    /// size of ImageArray for dylibs in this cache
+    pub dylibs_image_array_size: U64<E>,
+    /// (unslid) address of trie of indexes of all cached dylibs
+    pub dylibs_trie_addr: U64<E>,
+    /// size of trie of cached dylib paths
+    pub dylibs_trie_size: U64<E>,
+    /// (unslid) address of ImageArray for dylibs and bundles with dlopen closures
+    pub other_image_array_addr: U64<E>,
+    /// size of ImageArray for dylibs and bundles with dlopen closures
+    pub other_image_array_size: U64<E>,
+    /// (unslid) address of trie of indexes of all dylibs and bundles with dlopen closures
+    pub other_trie_addr: U64<E>,
+    /// size of trie of dylibs and bundles with dlopen closures
+    pub other_trie_size: U64<E>,
+    /// file offset to first dyld_cache_mapping_and_slide_info
+    pub mapping_with_slide_offset: U32<E>,
+    /// number of dyld_cache_mapping_and_slide_info entries
+    pub mapping_with_slide_count: U32<E>,
+    /// unused
+    pub dylibs_pbl_state_array_addr_unused: U64<E>,
+    /// (unslid) address of PrebuiltLoaderSet of all cached dylibs
+    pub dylibs_pbl_set_addr: U64<E>,
+    /// (unslid) address of pool of PrebuiltLoaderSet for each program
+    pub programs_pbl_set_pool_addr: U64<E>,
+    /// size of pool of PrebuiltLoaderSet for each program
+    pub programs_pbl_set_pool_size: U64<E>,
+    /// (unslid) address of trie mapping program path to PrebuiltLoaderSet
+    pub program_trie_addr: U64<E>,
+    /// OS Version of dylibs in this cache for the main platform
+    pub os_version: U32<E>,
+    /// e.g. iOSMac on macOS
+    pub alt_platform: U32<E>,
+    /// e.g. 14.0 for iOSMac
+    pub alt_os_version: U32<E>,
+    reserved1: [u8; 4],
+    /// VM offset from cache_header* to Swift optimizations header
+    pub swift_opts_offset: U64<E>,
+    /// size of Swift optimizations header
+    pub swift_opts_size: U64<E>,
+    /// file offset to first dyld_subcache_entry
+    pub sub_cache_array_offset: U32<E>,
+    /// number of subCache entries
+    pub sub_cache_array_count: U32<E>,
+    /// unique value for the shared cache file containing unmapped local symbols
+    pub symbol_file_uuid: [u8; 16],
+    /// (unslid) address of the start of where Rosetta can add read-only/executable data
+    pub rosetta_read_only_addr: U64<E>,
+    /// maximum size of the Rosetta read-only/executable region
+    pub rosetta_read_only_size: U64<E>,
+    /// (unslid) address of the start of where Rosetta can add read-write data
+    pub rosetta_read_write_addr: U64<E>,
+    /// maximum size of the Rosetta read-write region
+    pub rosetta_read_write_size: U64<E>,
     /// file offset to first dyld_cache_image_info
-    /// Use this  instead of images_offset if mapping_offset is at least 0x1c4.
-    pub images_across_all_subcaches_offset: U32<E>, // offset: 0x1c0
+    pub images_offset: U32<E>,
     /// number of dyld_cache_image_info entries
-    /// Use this  instead of images_count if mapping_offset is at least 0x1c4.
-    pub images_across_all_subcaches_count: U32<E>, // offset: 0x1c4
+    pub images_count: U32<E>,
+    /// 0 for development, 1 for production, when cacheType is multi-cache(2)
+    pub cache_sub_type: U32<E>,
+    /// VM offset from cache_header* to ObjC optimizations header
+    pub objc_opts_offset: U64<E>,
+    /// size of ObjC optimizations header
+    pub objc_opts_size: U64<E>,
+    /// VM offset from cache_header* to embedded cache atlas for process introspection
+    pub cache_atlas_offset: U64<E>,
+    /// size of embedded cache atlas
+    pub cache_atlas_size: U64<E>,
+    /// VM offset from cache_header* to the location of dyld_cache_dynamic_data_header
+    pub dynamic_data_offset: U64<E>,
+    /// maximum size of space reserved from dynamic data
+    pub dynamic_data_max_size: U64<E>,
 }
 
 /// Corresponds to struct dyld_cache_mapping_info from dyld_cache_format.h.
@@ -347,6 +479,40 @@ pub struct DyldCacheMappingInfo<E: Endian> {
     pub init_prot: U32<E>,
 }
 
+// Contains the flags for the dyld_cache_mapping_and_slide_info flags field
+pub const DYLD_CACHE_MAPPING_AUTH_DATA: u64 = 1 << 0;
+pub const DYLD_CACHE_MAPPING_DIRTY_DATA: u64 = 1 << 1;
+pub const DYLD_CACHE_MAPPING_CONST_DATA: u64 = 1 << 2;
+pub const DYLD_CACHE_MAPPING_TEXT_STUBS: u64 = 1 << 3;
+pub const DYLD_CACHE_DYNAMIC_CONFIG_DATA: u64 = 1 << 4;
+
+/// Corresponds to struct dyld_cache_mapping_and_slide_info from dyld_cache_format.h.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DyldCacheMappingAndSlideInfo<E: Endian> {
+    pub address: U64<E>,
+    pub size: U64<E>,
+    pub file_offset: U64<E>,
+    pub slide_info_file_offset: U64<E>,
+    pub slide_info_file_size: U64<E>,
+    pub flags: U64<E>,
+    pub max_prot: U32<E>,
+    pub init_prot: U32<E>,
+}
+
+/// Corresponds to struct dyld_cache_slide_info5 from dyld_cache_format.h.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct DyldCacheSlideInfo5<E: Endian> {
+    pub version: U32<E>,   // currently 5
+    pub page_size: U32<E>, // currently 4096 (may also be 16384)
+    pub page_starts_count: U32<E>,
+    reserved1: [u8; 4],
+    pub value_add: U64<E>,
+}
+
+pub const DYLD_CACHE_SLIDE_V5_PAGE_ATTR_NO_REBASE: u16 = 0xFFFF; // page has no rebasing
+
 /// Corresponds to struct dyld_cache_image_info from dyld_cache_format.h.
 #[derive(Debug, Clone, Copy)]
 #[repr(C)]
@@ -358,6 +524,54 @@ pub struct DyldCacheImageInfo<E: Endian> {
     pub pad: U32<E>,
 }
 
+/// Corresponds to struct dyld_cache_slide_pointer5 from dyld_cache_format.h.
+#[derive(Debug, Clone, Copy)]
+pub struct DyldCacheSlidePointer5(pub u64);
+
+impl DyldCacheSlidePointer5 {
+    fn is_auth(&self) -> bool {
+        (self.0 & 0x8000_0000_0000_0000) != 0
+    }
+
+    pub fn value(&self, value_add: u64) -> u64 {
+        let runtime_offset: u64 = self.0 & 0x3_ffff_ffff;
+
+        if self.is_auth() {
+            runtime_offset + value_add
+        } else {
+            let high8: u64 = (self.0 >> 34) & 0xff;
+
+            high8 << 56 | (runtime_offset + value_add)
+        }
+    }
+
+    pub fn auth(&self) -> Option<Ptrauth> {
+        if self.is_auth() {
+            let diversity: u16 = ((self.0 >> 34) & 0xffff) as u16;
+            let addr_div: bool = ((self.0 >> 50) & 0x1) != 0;
+
+            let key_is_data: bool = ((self.0 >> 51) & 0x1) != 0;
+            let key = if key_is_data {
+                PtrauthKey::DA
+            } else {
+                PtrauthKey::IA
+            };
+
+            Some(Ptrauth {
+                key,
+                diversity,
+                addr_div,
+            })
+        } else {
+            None
+        }
+    }
+
+    pub fn next(&self) -> u64 {
+        (self.0 >> 52) & 0x7ff
+    }
+}
+
 /// Added in dyld-940, which shipped with macOS 12 / iOS 15.
 /// Originally called `dyld_subcache_entry`, renamed to `dyld_subcache_entry_v1`
 /// in dyld-1042.1.
@@ -3245,7 +3459,9 @@ unsafe_impl_pod!(FatHeader, FatArch32, FatArch64,);
 unsafe_impl_endian_pod!(
     DyldCacheHeader,
     DyldCacheMappingInfo,
+    DyldCacheMappingAndSlideInfo,
     DyldCacheImageInfo,
+    DyldCacheSlideInfo5,
     DyldSubCacheEntryV1,
     DyldSubCacheEntryV2,
     MachHeader32,
diff --git a/src/read/macho/dyld_cache.rs b/src/read/macho/dyld_cache.rs
index 6375a369..fef1e8e0 100644
--- a/src/read/macho/dyld_cache.rs
+++ b/src/read/macho/dyld_cache.rs
@@ -1,7 +1,8 @@
 use alloc::vec::Vec;
-use core::slice;
+use core::fmt::{self, Debug};
+use core::{mem, slice};
 
-use crate::endian::{Endian, Endianness};
+use crate::endian::{Endian, Endianness, U16, U32, U64};
 use crate::macho;
 use crate::read::{Architecture, Error, File, ReadError, ReadRef, Result};
 
@@ -15,7 +16,7 @@ where
     endian: E,
     data: R,
     subcaches: Vec<DyldSubCache<'data, E, R>>,
-    mappings: &'data [macho::DyldCacheMappingInfo<E>],
+    mappings: DyldCacheMappingSlice<'data, E, R>,
     images: &'data [macho::DyldCacheImageInfo<E>],
     arch: Architecture,
 }
@@ -28,7 +29,369 @@ where
     R: ReadRef<'data>,
 {
     data: R,
-    mappings: &'data [macho::DyldCacheMappingInfo<E>],
+    mappings: DyldCacheMappingSlice<'data, E, R>,
+}
+
+/// Information about a mapping.
+#[derive(Clone, Copy)]
+pub enum DyldCacheMapping<'data, E = Endianness, R = &'data [u8]>
+where
+    E: Endian,
+    R: ReadRef<'data>,
+{
+    /// Corresponds to struct dyld_cache_mapping_info from dyld_cache_format.h.
+    V1 {
+        /// The mapping endianness
+        endian: E,
+        /// The mapping data
+        data: R,
+        /// The mapping information
+        info: &'data macho::DyldCacheMappingInfo<E>,
+    },
+    /// Corresponds to struct dyld_cache_mapping_and_slide_info from dyld_cache_format.h.
+    V2 {
+        /// The mapping endianness
+        endian: E,
+        /// The mapping data
+        data: R,
+        /// The mapping information
+        info: &'data macho::DyldCacheMappingAndSlideInfo<E>,
+    },
+}
+
+impl<'data, E, R> Debug for DyldCacheMapping<'data, E, R>
+where
+    E: Endian,
+    R: ReadRef<'data>,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("DyldCacheMapping")
+            .field("address", &format_args!("{:#x}", self.address()))
+            .field("size", &format_args!("{:#x}", self.size()))
+            .field("file_offset", &format_args!("{:#x}", self.file_offset()))
+            .field("max_prot", &format_args!("{:#x}", self.max_prot()))
+            .field("init_prot", &format_args!("{:#x}", self.init_prot()))
+            .finish()
+    }
+}
+
+impl<'data, E, R> DyldCacheMapping<'data, E, R>
+where
+    E: Endian,
+    R: ReadRef<'data>,
+{
+    /// The mapping address
+    pub fn address(&self) -> u64 {
+        match self {
+            Self::V1 {
+                endian,
+                data: _,
+                info,
+            } => info.address.get(*endian),
+            Self::V2 {
+                endian,
+                data: _,
+                info,
+            } => info.address.get(*endian),
+        }
+    }
+
+    /// The mapping size
+    pub fn size(&self) -> u64 {
+        match self {
+            Self::V1 {
+                endian,
+                data: _,
+                info,
+            } => info.size.get(*endian),
+            Self::V2 {
+                endian,
+                data: _,
+                info,
+            } => info.size.get(*endian),
+        }
+    }
+
+    /// The mapping file offset
+    pub fn file_offset(&self) -> u64 {
+        match self {
+            Self::V1 {
+                endian,
+                data: _,
+                info,
+            } => info.file_offset.get(*endian),
+            Self::V2 {
+                endian,
+                data: _,
+                info,
+            } => info.file_offset.get(*endian),
+        }
+    }
+
+    /// The mapping maximum protection
+    pub fn max_prot(&self) -> u32 {
+        match self {
+            Self::V1 {
+                endian,
+                data: _,
+                info,
+            } => info.max_prot.get(*endian),
+            Self::V2 {
+                endian,
+                data: _,
+                info,
+            } => info.max_prot.get(*endian),
+        }
+    }
+
+    /// The mapping initial protection
+    pub fn init_prot(&self) -> u32 {
+        match self {
+            Self::V1 {
+                endian,
+                data: _,
+                info,
+            } => info.init_prot.get(*endian),
+            Self::V2 {
+                endian,
+                data: _,
+                info,
+            } => info.init_prot.get(*endian),
+        }
+    }
+
+    /// The mapping data
+    pub fn data(&self) -> Result<&'data [u8]> {
+        match self {
+            Self::V1 { endian, data, info } => data
+                .read_bytes_at(info.file_offset.get(*endian), info.size.get(*endian))
+                .read_error("Failed to read bytes for mapping"),
+            Self::V2 { endian, data, info } => data
+                .read_bytes_at(info.file_offset.get(*endian), info.size.get(*endian))
+                .read_error("Failed to read bytes for mapping"),
+        }
+    }
+
+    /// Relocations for the mapping
+    pub fn relocations(self) -> Result<DyldCacheRelocationMappingIterator<'data, E, R>> {
+        match self {
+            Self::V1 { .. } => Ok(DyldCacheRelocationMappingIterator::empty()),
+            Self::V2 { endian, data, info } => {
+                if let Some(slide) = info.slide(endian, data)? {
+                    Ok(DyldCacheRelocationMappingIterator::slide(
+                        data, endian, info, slide,
+                    ))
+                } else {
+                    Ok(DyldCacheRelocationMappingIterator::empty())
+                }
+            }
+        }
+    }
+}
+
+/// An iterator over relocations in a mapping
+#[derive(Debug)]
+pub enum DyldCacheRelocationMappingIterator<'data, E = Endianness, R = &'data [u8]>
+where
+    E: Endian,
+    R: ReadRef<'data>,
+{
+    /// Empty
+    Empty,
+    /// Slide
+    Slide {
+        /// The mapping data
+        data: R,
+        /// Endian
+        endian: E,
+        /// The mapping information
+        info: &'data macho::DyldCacheMappingAndSlideInfo<E>,
+        /// The mapping slide information
+        slide: DyldCacheSlideInfoSlice<'data, E>,
+        /// Page starts
+        page_index: u64,
+        /// Page iterator
+        iter: Option<DyldCacheRelocationPageIterator<'data, E, R>>,
+    },
+}
+
+impl<'data, E, R> DyldCacheRelocationMappingIterator<'data, E, R>
+where
+    E: Endian,
+    R: ReadRef<'data>,
+{
+    /// Slide iterator
+    pub fn slide(
+        data: R,
+        endian: E,
+        info: &'data macho::DyldCacheMappingAndSlideInfo<E>,
+        slide: DyldCacheSlideInfoSlice<'data, E>,
+    ) -> Self {
+        Self::Slide {
+            data,
+            endian,
+            info,
+            slide,
+            page_index: 0,
+            iter: None,
+        }
+    }
+
+    /// Empty iterator
+    pub fn empty() -> Self {
+        Self::Empty
+    }
+}
+
+impl<'data, E, R> Iterator for DyldCacheRelocationMappingIterator<'data, E, R>
+where
+    E: Endian,
+    R: ReadRef<'data>,
+{
+    type Item = Result<DyldRelocation>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        match self {
+            Self::Empty => None,
+            Self::Slide {
+                data,
+                endian,
+                info,
+                slide,
+                page_index,
+                iter,
+            } => loop {
+                if let Some(reloc) = iter.as_mut().and_then(|iter| iter.next()) {
+                    return Some(reloc);
+                }
+
+                match slide {
+                    DyldCacheSlideInfoSlice::V5(slide, page_starts) => {
+                        if *page_index < slide.page_starts_count.get(*endian).into() {
+                            let page_start: u16 = page_starts[*page_index as usize].get(*endian);
+
+                            if page_start != macho::DYLD_CACHE_SLIDE_V5_PAGE_ATTR_NO_REBASE {
+                                *iter = Some(DyldCacheRelocationPageIterator::V5 {
+                                    data: *data,
+                                    endian: *endian,
+                                    info: *info,
+                                    slide: *slide,
+                                    page_index: *page_index,
+                                    page_offset: Some(page_start.into()),
+                                });
+                            } else {
+                                *iter = None;
+                            }
+
+                            *page_index += 1;
+                        } else {
+                            return None;
+                        }
+                    }
+                }
+            },
+        }
+    }
+}
+
+/// A versioned iterator over relocations in a page
+#[derive(Debug)]
+pub enum DyldCacheRelocationPageIterator<'data, E = Endianness, R = &'data [u8]>
+where
+    E: Endian,
+    R: ReadRef<'data>,
+{
+    /// Corresponds to struct dyld_cache_slide_info5 from dyld_cache_format.h.
+    V5 {
+        /// The mapping data
+        data: R,
+        /// Endian
+        endian: E,
+        /// The mapping information
+        info: &'data macho::DyldCacheMappingAndSlideInfo<E>,
+        /// The mapping slide information
+        slide: &'data macho::DyldCacheSlideInfo5<E>,
+        /// Mapping page index
+        page_index: u64,
+        /// The current offset into the page
+        page_offset: Option<u64>,
+    },
+}
+
+impl<'data, E, R> Iterator for DyldCacheRelocationPageIterator<'data, E, R>
+where
+    E: Endian,
+    R: ReadRef<'data>,
+{
+    type Item = Result<DyldRelocation>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        match self {
+            Self::V5 {
+                data,
+                endian,
+                info,
+                slide,
+                page_index,
+                page_offset,
+            } => {
+                if let Some(offset) = *page_offset {
+                    let mapping_offset: u64 = *page_index * slide.page_size.get(*endian) as u64;
+                    let file_offset: u64 = info.file_offset.get(*endian) + mapping_offset + offset;
+                    let pointer = match data.read_at::<U64<E>>(file_offset) {
+                        Ok(pointer) => pointer.get(*endian),
+                        Err(_) => {
+                            return Some(Err(Error("Failed to read file offset")));
+                        }
+                    };
+                    let pointer = macho::DyldCacheSlidePointer5(pointer);
+
+                    let next = pointer.next();
+                    if next == 0 {
+                        *page_offset = None;
+                    } else {
+                        *page_offset = Some(offset + (next * 8));
+                    }
+
+                    let address = info.address.get(*endian) + mapping_offset + offset;
+                    let value_add = slide.value_add.get(*endian);
+                    let value = pointer.value(value_add);
+                    let auth = pointer.auth();
+                    Some(Ok(DyldRelocation {
+                        address,
+                        file_offset,
+                        value,
+                        auth,
+                    }))
+                } else {
+                    None
+                }
+            }
+        }
+    }
+}
+
+/// A cache mapping relocation.
+pub struct DyldRelocation {
+    /// The address of the relocation
+    pub address: u64,
+    /// The offset of the relocation within the mapping
+    pub file_offset: u64,
+    /// The relocation value
+    pub value: u64,
+    /// The value auth context
+    pub auth: Option<macho::Ptrauth>,
+}
+
+impl Debug for DyldRelocation {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("DyldRelocation")
+            .field("address", &format_args!("{:#x}", self.address))
+            .field("file_offset", &format_args!("{:#x}", self.file_offset))
+            .field("value", &format_args!("{:#x}", self.value))
+            .field("auth", &self.auth)
+            .finish()
+    }
 }
 
 /// A slice of structs describing each subcache. The struct gained
@@ -43,6 +406,143 @@ pub enum DyldSubCacheSlice<'data, E: Endian> {
     V2(&'data [macho::DyldSubCacheEntryV2<E>]),
 }
 
+/// An enum of arrays containing dyld cache mappings
+#[derive(Debug, Clone, Copy)]
+#[non_exhaustive]
+pub enum DyldCacheMappingSlice<'data, E = Endianness, R = &'data [u8]>
+where
+    E: Endian,
+    R: ReadRef<'data>,
+{
+    /// Corresponds to an array of struct dyld_cache_mapping_info
+    V1 {
+        /// The mapping endianness
+        endian: E,
+        /// The mapping data
+        data: R,
+        /// The slice of mapping info
+        info: &'data [macho::DyldCacheMappingInfo<E>],
+    },
+    /// Corresponds to an array of struct dyld_cache_mapping_and_slide_info
+    V2 {
+        /// The mapping endianness
+        endian: E,
+        /// The mapping data
+        data: R,
+        /// The slice of mapping info
+        info: &'data [macho::DyldCacheMappingAndSlideInfo<E>],
+    },
+}
+
+impl<'data, E, R> DyldCacheMappingSlice<'data, E, R>
+where
+    E: Endian,
+    R: ReadRef<'data>,
+{
+    /// Return a slice iterator
+    pub fn iter(self) -> DyldCacheMappingIterator<'data, E, R> {
+        match self {
+            Self::V1 { endian, data, info } => DyldCacheMappingIterator::V1 {
+                endian,
+                data,
+                iter: info.iter(),
+            },
+            Self::V2 { endian, data, info } => DyldCacheMappingIterator::V2 {
+                endian,
+                data,
+                iter: info.iter(),
+            },
+        }
+    }
+
+    /// Find the file offset of the image by looking up its address in the mappings.
+    pub fn address_to_file_offset(&self, address: u64) -> Option<u64> {
+        for mapping in self.iter() {
+            let mapping_address = mapping.address();
+            if address >= mapping_address && address < mapping_address.wrapping_add(mapping.size())
+            {
+                return Some(address - mapping_address + mapping.file_offset());
+            }
+        }
+        None
+    }
+}
+
+/// An iterator over all the mappings in a dyld shared cache.
+#[derive(Debug)]
+pub enum DyldCacheMappingIterator<'data, E = Endianness, R = &'data [u8]>
+where
+    E: Endian,
+    R: ReadRef<'data>,
+{
+    /// Corresponds to struct dyld_cache_mapping_info from dyld_cache_format.h.
+    V1 {
+        /// The mapping endianness
+        endian: E,
+        /// The mapping data
+        data: R,
+        /// The mapping info iterator
+        iter: slice::Iter<'data, macho::DyldCacheMappingInfo<E>>,
+    },
+    /// Corresponds to struct dyld_cache_mapping_and_slide_info from dyld_cache_format.h.
+    V2 {
+        /// The mapping endianness
+        endian: E,
+        /// The mapping data
+        data: R,
+        /// The mapping info iterator
+        iter: slice::Iter<'data, macho::DyldCacheMappingAndSlideInfo<E>>,
+    },
+}
+
+impl<'data, E, R> Iterator for DyldCacheMappingIterator<'data, E, R>
+where
+    E: Endian,
+    R: ReadRef<'data>,
+{
+    type Item = DyldCacheMapping<'data, E, R>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        match self {
+            Self::V1 { endian, data, iter } => {
+                let info = iter.next()?;
+                Some(DyldCacheMapping::V1 {
+                    endian: *endian,
+                    data: *data,
+                    info,
+                })
+            }
+            Self::V2 { endian, data, iter } => {
+                let info = iter.next()?;
+                Some(DyldCacheMapping::V2 {
+                    endian: *endian,
+                    data: *data,
+                    info,
+                })
+            }
+        }
+    }
+}
+
+/// An enum of arrays containing dyld cache mappings
+#[derive(Clone, Copy)]
+#[non_exhaustive]
+pub enum DyldCacheSlideInfoSlice<'data, E: Endian> {
+    /// Corresponds to struct dyld_cache_slide_info5 from dyld_cache_format.h.
+    V5(&'data macho::DyldCacheSlideInfo5<E>, &'data [U16<E>]),
+}
+
+impl<E: Endian> Debug for DyldCacheSlideInfoSlice<'_, E> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::V5(info, _) => f
+                .debug_struct("DyldCacheSlideInfoSlice::V5")
+                .field("info", info)
+                .finish(),
+        }
+    }
+}
+
 // This is the offset of the end of the images_across_all_subcaches_count field.
 const MIN_HEADER_SIZE_SUBCACHES_V1: u32 = 0x1c8;
 
@@ -96,11 +596,11 @@ where
             };
             let uuids = v1.iter().map(|e| &e.uuid).chain(v2.iter().map(|e| &e.uuid));
             for (&data, uuid) in subcache_data.iter().zip(uuids) {
-                let sc_header = macho::DyldCacheHeader::<E>::parse(data)?;
-                if &sc_header.uuid != uuid {
+                let header = macho::DyldCacheHeader::<E>::parse(data)?;
+                if &header.uuid != uuid {
                     return Err(Error("Unexpected SubCache UUID"));
                 }
-                let mappings = sc_header.mappings(endian, data)?;
+                let mappings = header.mappings(endian, data)?;
                 subcaches.push(DyldSubCache { data, mappings });
             }
         }
@@ -109,11 +609,11 @@ where
         // Other than the UUID verification, the symbols SubCache is currently unused.
         let _symbols_subcache = match symbols_subcache_data_and_uuid {
             Some((data, uuid)) => {
-                let sc_header = macho::DyldCacheHeader::<E>::parse(data)?;
-                if sc_header.uuid != uuid {
+                let header = macho::DyldCacheHeader::<E>::parse(data)?;
+                if header.uuid != uuid {
                     return Err(Error("Unexpected .symbols SubCache UUID"));
                 }
-                let mappings = sc_header.mappings(endian, data)?;
+                let mappings = header.mappings(endian, data)?;
                 Some(DyldSubCache { data, mappings })
             }
             None => None,
@@ -158,16 +658,25 @@ where
         }
     }
 
+    /// Return all the mappings in this cache.
+    pub fn mappings<'cache>(
+        &'cache self,
+    ) -> impl Iterator<Item = DyldCacheMapping<'data, E, R>> + 'cache {
+        self.mappings.iter().chain(
+            self.subcaches
+                .iter()
+                .flat_map(|subcache| subcache.mappings.iter()),
+        )
+    }
+
     /// Find the address in a mapping and return the cache or subcache data it was found in,
     /// together with the translated file offset.
     pub fn data_and_offset_for_address(&self, address: u64) -> Option<(R, u64)> {
-        if let Some(file_offset) = address_to_file_offset(address, self.endian, self.mappings) {
+        if let Some(file_offset) = self.mappings.address_to_file_offset(address) {
             return Some((self.data, file_offset));
         }
         for subcache in &self.subcaches {
-            if let Some(file_offset) =
-                address_to_file_offset(address, self.endian, subcache.mappings)
-            {
+            if let Some(file_offset) = subcache.mappings.address_to_file_offset(address) {
                 return Some((subcache.data, file_offset));
             }
         }
@@ -241,6 +750,44 @@ where
     }
 }
 
+impl<E: Endian> macho::DyldCacheMappingAndSlideInfo<E> {
+    /// Return the (optional) array of slide information structs
+    pub fn slide<'data, R: ReadRef<'data>>(
+        &self,
+        endian: E,
+        data: R,
+    ) -> Result<Option<DyldCacheSlideInfoSlice<'data, E>>> {
+        match self.slide_info_file_size.get(endian) {
+            0 => Ok(None),
+            _ => {
+                let slide_info_file_offset = self.slide_info_file_offset.get(endian);
+                let version = data
+                    .read_at::<U32<E>>(slide_info_file_offset)
+                    .read_error("Invalid slide info file offset size or alignment")?
+                    .get(endian);
+                match version {
+                    5 => {
+                        let slide = data
+                            .read_at::<macho::DyldCacheSlideInfo5<E>>(slide_info_file_offset)
+                            .read_error("Invalid dyld cache slide info size or alignment")?;
+                        let page_starts_offset = slide_info_file_offset
+                            .checked_add(mem::size_of::<macho::DyldCacheSlideInfo5<E>>() as u64)
+                            .read_error("Page starts overflow")?;
+                        let page_starts = data
+                            .read_slice_at::<U16<E>>(
+                                page_starts_offset,
+                                slide.page_starts_count.get(endian) as usize,
+                            )
+                            .read_error("Invalid page starts size or alignment")?;
+                        Ok(Some(DyldCacheSlideInfoSlice::V5(slide, page_starts)))
+                    }
+                    _ => Err(Error("Unsupported dyld_cache_slide_info version")),
+                }
+            }
+        }
+    }
+}
+
 impl<E: Endian> macho::DyldCacheHeader<E> {
     /// Read the dyld cache header.
     pub fn parse<'data, R: ReadRef<'data>>(data: R) -> Result<&'data Self> {
@@ -274,12 +821,24 @@ impl<E: Endian> macho::DyldCacheHeader<E> {
         &self,
         endian: E,
         data: R,
-    ) -> Result<&'data [macho::DyldCacheMappingInfo<E>]> {
-        data.read_slice_at::<macho::DyldCacheMappingInfo<E>>(
-            self.mapping_offset.get(endian).into(),
-            self.mapping_count.get(endian) as usize,
-        )
-        .read_error("Invalid dyld cache mapping size or alignment")
+    ) -> Result<DyldCacheMappingSlice<'data, E, R>> {
+        if self.mapping_with_slide_offset.get(endian) != 0 {
+            let info = data
+                .read_slice_at::<macho::DyldCacheMappingAndSlideInfo<E>>(
+                    self.mapping_with_slide_offset.get(endian).into(),
+                    self.mapping_with_slide_count.get(endian) as usize,
+                )
+                .read_error("Invalid dyld cache mapping size or alignment")?;
+            Ok(DyldCacheMappingSlice::V2 { endian, data, info })
+        } else {
+            let info = data
+                .read_slice_at::<macho::DyldCacheMappingInfo<E>>(
+                    self.mapping_offset.get(endian).into(),
+                    self.mapping_count.get(endian) as usize,
+                )
+                .read_error("Invalid dyld cache mapping size or alignment")?;
+            Ok(DyldCacheMappingSlice::V1 { endian, data, info })
+        }
     }
 
     /// Return the information about subcaches, if present.
@@ -294,16 +853,16 @@ impl<E: Endian> macho::DyldCacheHeader<E> {
         if header_size >= MIN_HEADER_SIZE_SUBCACHES_V2 {
             let subcaches = data
                 .read_slice_at::<macho::DyldSubCacheEntryV2<E>>(
-                    self.subcaches_offset.get(endian).into(),
-                    self.subcaches_count.get(endian) as usize,
+                    self.sub_cache_array_offset.get(endian).into(),
+                    self.sub_cache_array_count.get(endian) as usize,
                 )
                 .read_error("Invalid dyld subcaches size or alignment")?;
             Ok(Some(DyldSubCacheSlice::V2(subcaches)))
         } else if header_size >= MIN_HEADER_SIZE_SUBCACHES_V1 {
             let subcaches = data
                 .read_slice_at::<macho::DyldSubCacheEntryV1<E>>(
-                    self.subcaches_offset.get(endian).into(),
-                    self.subcaches_count.get(endian) as usize,
+                    self.sub_cache_array_offset.get(endian).into(),
+                    self.sub_cache_array_count.get(endian) as usize,
                 )
                 .read_error("Invalid dyld subcaches size or alignment")?;
             Ok(Some(DyldSubCacheSlice::V1(subcaches)))
@@ -315,7 +874,7 @@ impl<E: Endian> macho::DyldCacheHeader<E> {
     /// Return the UUID for the .symbols subcache, if present.
     pub fn symbols_subcache_uuid(&self, endian: E) -> Option<[u8; 16]> {
         if self.mapping_offset.get(endian) >= MIN_HEADER_SIZE_SUBCACHES_V1 {
-            let uuid = self.symbols_subcache_uuid;
+            let uuid = self.symbol_file_uuid;
             if uuid != [0; 16] {
                 return Some(uuid);
             }
@@ -331,14 +890,14 @@ impl<E: Endian> macho::DyldCacheHeader<E> {
     ) -> Result<&'data [macho::DyldCacheImageInfo<E>]> {
         if self.mapping_offset.get(endian) >= MIN_HEADER_SIZE_SUBCACHES_V1 {
             data.read_slice_at::<macho::DyldCacheImageInfo<E>>(
-                self.images_across_all_subcaches_offset.get(endian).into(),
-                self.images_across_all_subcaches_count.get(endian) as usize,
+                self.images_offset.get(endian).into(),
+                self.images_count.get(endian) as usize,
             )
             .read_error("Invalid dyld cache image size or alignment")
         } else {
             data.read_slice_at::<macho::DyldCacheImageInfo<E>>(
-                self.images_offset.get(endian).into(),
-                self.images_count.get(endian) as usize,
+                self.images_offset_old.get(endian).into(),
+                self.images_count_old.get(endian) as usize,
             )
             .read_error("Invalid dyld cache image size or alignment")
         }
@@ -355,30 +914,14 @@ impl<E: Endian> macho::DyldCacheImageInfo<E> {
     }
 
     /// Find the file offset of the image by looking up its address in the mappings.
-    pub fn file_offset(
+    pub fn file_offset<'data, R: ReadRef<'data>>(
         &self,
         endian: E,
-        mappings: &[macho::DyldCacheMappingInfo<E>],
+        mappings: &DyldCacheMappingSlice<'data, E, R>,
     ) -> Result<u64> {
         let address = self.address.get(endian);
-        address_to_file_offset(address, endian, mappings)
+        mappings
+            .address_to_file_offset(address)
             .read_error("Invalid dyld cache image address")
     }
 }
-
-/// Find the file offset of the image by looking up its address in the mappings.
-pub fn address_to_file_offset<E: Endian>(
-    address: u64,
-    endian: E,
-    mappings: &[macho::DyldCacheMappingInfo<E>],
-) -> Option<u64> {
-    for mapping in mappings {
-        let mapping_address = mapping.address.get(endian);
-        if address >= mapping_address
-            && address < mapping_address.wrapping_add(mapping.size.get(endian))
-        {
-            return Some(address - mapping_address + mapping.file_offset.get(endian));
-        }
-    }
-    None
-}