1use crate::error::Result;
2use crate::format::io::pod::{self, RawMethodListHeader, RawPropertyT};
3use crate::model::addr::Va;
4use crate::objc::resolve::ObjCResolver;
5use crate::objc::types::{METHOD_LIST_ENTSIZE_MASK, ObjCProperty};
6
7pub fn parse_property_list(resolver: &ObjCResolver<'_>, va: Va) -> Result<Vec<ObjCProperty>> {
9 parse_property_list_with_kind(resolver, va, false)
10}
11
12pub fn parse_property_list_with_kind(
14 resolver: &ObjCResolver<'_>,
15 va: Va,
16 is_class: bool,
17) -> Result<Vec<ObjCProperty>> {
18 let offset = resolver.va_to_offset(va)?;
19 let data = resolver.macho().bytes();
20 let endian = resolver.endian();
21
22 let header: RawMethodListHeader = pod::read_pod(data, offset.as_usize())?;
23 let entsize_and_flags = endian.interpret_u32(header.entsize_and_flags);
24 let count = endian.interpret_u32(header.count) as usize;
25 let header_size = size_of::<RawMethodListHeader>();
26
27 let entsize = (entsize_and_flags & METHOD_LIST_ENTSIZE_MASK) as usize;
28 let entry_size = if entsize > 0 {
29 entsize
30 } else {
31 size_of::<RawPropertyT>()
32 };
33
34 let mut props = Vec::with_capacity(count.min(1000));
35
36 for i in 0..count {
37 let entry_offset = offset.as_usize() + header_size + i * entry_size;
38
39 let name_ptr = resolver.read_pointer_at_offset(entry_offset as u64)?;
40 let attr_ptr = resolver.read_pointer_at_offset(entry_offset as u64 + 8)?;
41
42 let name = match name_ptr {
43 Some(va) => resolver.read_cstring(va).unwrap_or("<invalid>"),
44 None => "<null>",
45 };
46 let attributes = match attr_ptr {
47 Some(va) => resolver.read_cstring(va).unwrap_or(""),
48 None => "",
49 };
50
51 props.push(ObjCProperty {
52 name: name.to_string(),
53 attributes: attributes.to_string(),
54 is_class,
55 });
56 }
57
58 Ok(props)
59}