def parse_symbols(file_num_to_consider: List[str]) -> Set[str]: var.get(NL) current_line = var.get(CL) assert current_line == "# Address Size File Name" var.get(NL) symbol_line_pattern = re.compile( ".*?\[\s*(?P<file_num>\d+)\]\s*[\+-]\[(?P<obj_name>\S+)\s+(?P<method_name>\S+?)\]" ) current_line = var.get(CL) objects_name = set() while current_line: if current_line.startswith("#"): break else: m = symbol_line_pattern.match(current_line) if m and m.group('file_num') in file_num_to_consider: objects_name.add(m.group('obj_name')) var.get(NL) current_line = var.get(CL) return objects_name
def _move_to_seg_and_sect(seg, sect): current_line = var.get(CL) while current_line: m = new_section_pattern.match(current_line) if m and m.group('segname') == seg and m.group('sectname') == sect: var.get(NL) return var.get(NL) current_line = var.get(CL) raise Exception(f'segment: {seg} section: {sect} not found')
def parse_link_map(lp, pod=None): var.set(CF, open(lp, 'r')) var.get(NL) current_line = var.get(CL) #type:str file_num_to_consider = None object_names = None while current_line: if current_line.startswith("#"): if current_line.replace(" ", '') == object_file_start_line: file_num_to_consider = parse_object_files(pod=pod) elif current_line.replace(" ", '') == symbols_start_line: assert file_num_to_consider object_names = parse_symbols(file_num_to_consider) else: var.get(NL) else: var.get(NL) current_line = var.get(CL) assert object_names return object_names
def parse_object_files(pod=None) -> List: object_file_line_pattern = re.compile( "\[\s*(?P<file_num>\d+)\]\s+.+?\.a\((?P<file_name>\S+)\.o\)") var.get(NL) file_num_belongs_to_pod = [] current_line = var.get(CL) # type:str while current_line: if current_line.startswith("#"): break if pod and pod not in current_line: pass else: m = object_file_line_pattern.match(current_line) if m: file_num_belongs_to_pod.append(m.group('file_num')) var.get(NL) current_line = var.get(CL) return file_num_belongs_to_pod
def parse_class_list(ep) -> dict: current_file = subprocess.Popen(['otool', '-oV', ep], stdout=subprocess.PIPE).stdout var.set(CF, current_file) var.get(NL) _move_to_seg_and_sect('__DATA', '__objc_classlist') class_objects = {} current_line = var.get(CL) while current_line: if new_class_pattern.match(current_line): class_object = _parse_implemented_class() class_objects[class_object.name] = class_object elif new_section_pattern.match(current_line): break else: var.get(NL) current_line = var.get(CL) return class_objects
def parse_referenced_methods(ep) -> List: current_file = subprocess.Popen( ['otool', '-v', '-s', '__DATA', '__objc_selrefs', ep], stdout=subprocess.PIPE).stdout var.set(CF, current_file) var.get(NL) _move_to_seg_and_sect('__DATA', '__objc_selrefs') referenced_methods = [] pattern = re.compile( "[0-9a-f]{16}\s*__TEXT:__objc_methname:(?P<method>\S+)") current_line = var.get(CL) while current_line: m = pattern.match(current_line) if m: referenced_methods.append(m.group("method")) # logger.info(f"method {referenced_methods[-1]} referenced") var.get(NL) current_line = var.get(CL) return referenced_methods
def _parse_method_list(class_name) -> list: current_line = var.get(CL) r = [] if current_line.startswith("entsize"): var.get(NL) current_line = var.get(CL) assert current_line.startswith("count") count = int(current_line.split(" ")[-1]) var.get(NL) while count > 0: current_line = var.get(CL) assert current_line.startswith( "name"), f"error with class {class_name}" method_name = current_line.split()[-1] r.append(method_name) var.get(NL) assert var.get(CL).startswith( "types"), f"error with class {class_name}" var.get(NL) assert var.get(CL).startswith( "imp"), f"error with class {class_name}" var.get(NL) count -= 1 return r
def _parse_implemented_class() -> ObjectEntity: var.get(NL) name = None base_method_list = [] base_properties = [] base_protocols = [] while True: current_line = var.get(CL) #type:str if (not name) and current_line.startswith("name"): name = current_line.split(' ')[-1] var.get(NL) elif current_line.startswith("baseMethods"): assert name, f"error with line {current_line}" var.get(NL) base_method_list += _parse_method_list(name) elif current_line.startswith("baseProperties"): assert name, f"error with line {current_line}" var.get(NL) base_properties += _parse_property_list(name) elif current_line.startswith(data_baseProtocols): var.get(NL) base_protocols = _parse_protocol_list(name) elif new_class_pattern.match( current_line) or new_section_pattern.match(current_line): break else: var.get(NL) return ObjectEntity(name=name, base_method_list=base_method_list, base_property_list=base_properties, base_protocol_list=base_protocols)
def _parse_protocol_list(class_name: object) -> object: current_line = var.get(CL) r = [] if not current_line.startswith(data_baseProtocols_count): return r count = int(current_line.split(' ')[-1]) var.get(NL) while count > 0: var.get(NL) var.get(NL) current_line = var.get(CL) assert current_line.startswith(data_baseProtocols_name) r.append(current_line.split(' ')[-1]) while not current_line.startswith( data_baseProtocols_instanceProperties): var.get(NL) current_line = var.get(CL) var.get(NL) current_line = var.get(CL) count -= 1 assert current_line.startswith(ivars) return r
def _parse_property_list(class_name) -> List: current_line = var.get(CL) r = [] if current_line.startswith("entsize"): var.get(NL) current_line = var.get(CL) assert current_line.startswith("count") count = int(current_line.split(" ")[-1]) var.get(NL) while count > 0: current_line = var.get(CL) assert current_line.startswith( "name"), f"error with class {class_name}" property_name = current_line.split(' ')[-1] r.append(property_name) var.get(NL) assert var.get(CL).startswith( "attributes"), f"error with class {class_name}" var.get(NL) count -= 1 return r