1use crate::error::Result;
2use crate::format::io::pod::{self, RawIvarT64, RawMethodListHeader};
3use crate::model::addr::Va;
4use crate::objc::resolve::ObjCResolver;
5use crate::objc::types::{METHOD_LIST_ENTSIZE_MASK, ObjCIvar};
6
7pub fn parse_ivar_list(resolver: &ObjCResolver<'_>, va: Va) -> Result<Vec<ObjCIvar>> {
9 let offset = resolver.va_to_offset(va)?;
10 let data = resolver.macho().bytes();
11 let endian = resolver.endian();
12
13 let header: RawMethodListHeader = pod::read_pod(data, offset.as_usize())?;
14 let entsize_and_flags = endian.interpret_u32(header.entsize_and_flags);
15 let count = endian.interpret_u32(header.count) as usize;
16 let header_size = size_of::<RawMethodListHeader>();
17
18 let entsize = (entsize_and_flags & METHOD_LIST_ENTSIZE_MASK) as usize;
19 let entry_size = if entsize > 0 {
20 entsize
21 } else {
22 size_of::<RawIvarT64>()
23 };
24
25 let mut ivars = Vec::with_capacity(count.min(1000));
26
27 for i in 0..count {
28 let entry_offset = offset.as_usize() + header_size + i * entry_size;
29
30 let name_ptr = resolver.read_pointer_at_offset(entry_offset as u64 + 8)?;
31 let type_ptr = resolver.read_pointer_at_offset(entry_offset as u64 + 16)?;
32
33 let raw: RawIvarT64 = pod::read_pod(data, entry_offset)?;
35 let alignment = endian.interpret_u32(raw.alignment);
36 let size = endian.interpret_u32(raw.size);
37
38 let ivar_offset = resolver
40 .read_pointer_at_offset(entry_offset as u64)
41 .ok()
42 .flatten()
43 .and_then(|va| resolver.va_to_offset(va).ok())
44 .and_then(|offset| pod::read_pod::<u32>(data, offset.as_usize()).ok())
45 .map(|value| endian.interpret_u32(value));
46
47 let name = match name_ptr {
48 Some(va) => resolver.read_cstring(va).unwrap_or("<invalid>"),
49 None => "<null>",
50 };
51 let type_slot = pod::read_pod::<u64>(data, entry_offset + 16)
58 .map(|value| endian.interpret_u64(value))
59 .unwrap_or(0);
60 let type_encoding = match type_ptr {
61 Some(va) => resolver.read_cstring(va).ok().map(str::to_owned),
62 None if type_slot == 0 => Some(String::new()),
63 None => None,
64 };
65
66 ivars.push(ObjCIvar {
67 name: name.to_string(),
68 type_encoding,
69 offset: ivar_offset,
70 size,
71 alignment: 1u32.wrapping_shl(alignment),
72 });
73 }
74
75 Ok(ivars)
76}