def goto_referring_address(self, acting_client): current_address = self.get_address(acting_client) if current_address is None: return ERRMSG_NO_IDENTIFIABLE_DESTINATION addresses = list(disassembly.get_referring_addresses(self.disassembly_data, current_address)) if not len(addresses): return ERRMSG_NO_IDENTIFIABLE_DESTINATION # Addresses appear in numerical order. addresses.sort() # Symbols appear in place of addresses where they exist. converted_addresses = addresses[:] self._convert_addresses_to_symbols_where_possible(converted_addresses) address_rows = [] for i, address in enumerate(addresses): code_string = self.get_source_code_for_address(acting_client, address) address_rows.append((self._address_to_string(address), converted_addresses[i], code_string)) selected_address = acting_client.request_address_selection(TEXT_SELECT_REFERRING_ADDRESS_SHORT, TEXT_SELECT_REFERRING_ADDRESS_LONG, TEXT_GO_TO_SELECTION, address_rows, addresses) if selected_address is None: return False next_line_number = disassembly.get_line_number_for_address(self.disassembly_data, selected_address) if next_line_number is None: return ERRMSG_BUG_UNABLE_TO_GOTO_LINE self.set_line_number(acting_client, next_line_number) self.address_stack.append(current_address) return True
def pop_address(self, acting_client): if self.state_id != EditorState.STATE_LOADED: return ERRMSG_TODO_BAD_STATE_FUNCTIONALITY if not len(self.address_stack): return ERRMSG_NO_IDENTIFIABLE_DESTINATION address = self.address_stack.pop() # It is expected that if you can have pushed the address, there was a line number for it. line_number = disassembly.get_line_number_for_address(self.disassembly_data, address) self.set_line_number(acting_client, line_number)
def goto_address(self, acting_client): address = self.get_address(acting_client) if address is None: # Current line does not have an address. address = 0 result = acting_client.request_address(address) if result is None: # Cancelled / aborted. return # Convert an entered symbol name to it's address. if type(result) in types.StringTypes: result = disassembly.get_address_for_symbol(self.disassembly_data, result) if result is None: return ERRMSG_NO_IDENTIFIABLE_DESTINATION line_number = disassembly.get_line_number_for_address(self.disassembly_data, result) self.set_line_number(acting_client, line_number)
def push_address(self, acting_client): if self.state_id != EditorState.STATE_LOADED: return ERRMSG_TODO_BAD_STATE_FUNCTIONALITY current_address = self.get_address(acting_client) if current_address is None: return ERRMSG_BUG_UNKNOWN_ADDRESS operand_addresses = disassembly.get_referenced_symbol_addresses_for_line_number(self.disassembly_data, self.line_number) if len(operand_addresses) == 1: next_line_number = disassembly.get_line_number_for_address(self.disassembly_data, operand_addresses[0]) if next_line_number is None: return ERRMSG_BUG_UNABLE_TO_GOTO_LINE self.set_line_number(acting_client, next_line_number) self.address_stack.append(current_address) return elif len(operand_addresses) == 2: return ERRMSG_BUG_NO_OPERAND_SELECTION_MECHANISM return ERRMSG_NO_IDENTIFIABLE_DESTINATION
def load_file(self, acting_client): self.reset_state(acting_client) # Request a file name to load. result = acting_client.request_load_file() if result is None: return if type(result) in types.StringTypes: self.reset_state(acting_client) return result load_file, file_path = result self.state_id = EditorState.STATE_LOADING file_name = os.path.basename(file_path) is_saved_project = disassembly_persistence.check_is_project_file(load_file) for client in self.clients: client.event_load_start(client is acting_client, file_path) if is_saved_project: result = self._prolonged_action(acting_client, "TITLE_LOADING_PROJECT", "TEXT_GENERIC_LOADING", disassembly.load_project_file, load_file, file_name) else: new_options = disassembly.get_new_project_options(self.disassembly_data) identify_result = loaderlib.identify_file(load_file, file_name) # Parameters passed in, to help the client make up it's mind. if identify_result is not None: new_options.is_binary_file = False new_options.loader_load_address = loaderlib.get_load_address(identify_result[0]) new_options.loader_entrypoint_offset = loaderlib.get_entrypoint_address(identify_result[0]) new_options.loader_filetype = identify_result[1]["filetype"] new_options.loader_processor = identify_result[1]["processor"] else: new_options.is_binary_file = True new_options.loader_load_address = 0 new_options.loader_entrypoint_offset = 0 new_options.loader_filetype = loaderlib.constants.FILE_FORMAT_UNKNOWN new_options.loader_processor = "" # Prompt for new project option values. new_option_result = acting_client.request_new_project_option_values(new_options) if new_option_result is None or type(new_option_result) in types.StringTypes: self.reset_state(acting_client) return new_option_result result = self._prolonged_action(acting_client, "TITLE_LOADING_FILE", "TEXT_GENERIC_LOADING", disassembly.load_file, load_file, new_option_result, file_name) # Loading was cancelled. if result is None: self.reset_state(acting_client) return self.state_id = EditorState.STATE_LOADED self.disassembly_data, line_count = result # Register our event dispatching callbacks. disassembly.set_uncertain_reference_modification_func(self.disassembly_data, self._uncertain_reference_modification_callback) disassembly.set_symbol_insert_func(self.disassembly_data, self._symbol_insert_callback) disassembly.set_symbol_delete_func(self.disassembly_data, self._symbol_delete_callback) if line_count == 0: self.reset_state(acting_client) return ERRMSG_NOT_SUPPORTED_EXECUTABLE_FILE_FORMAT is_saved_project = disassembly_persistence.check_is_project_file(acting_client.get_load_file()) if is_saved_project: # User may have optionally chosen to not save the input file, as part of the project file. if not disassembly.is_segment_data_cached(self.disassembly_data): load_options = disassembly.get_new_project_options(self.disassembly_data) # Parameters passed in, to help the client make up it's mind. load_options.input_file_filesize = self.disassembly_data.file_size load_options.input_file_filename = self.disassembly_data.file_name load_options.input_file_checksum = self.disassembly_data.file_checksum # Parameters received out, our "return values". load_options.loader_file_path = None load_options = acting_client.request_load_project_option_values(load_options) if load_options.loader_file_path is None: self.reset_state(acting_client) return ERRMSG_INPUT_FILE_NOT_FOUND # Verify that the given input file is valid, or error descriptively. with open(load_options.loader_file_path, "rb") as input_data_file: input_data_file.seek(0, os.SEEK_END) errmsg = None if input_data_file.tell() != self.disassembly_data.file_size: errmsg = ERRMSG_INPUT_FILE_SIZE_DIFFERS elif util.calculate_file_checksum(input_data_file) != self.disassembly_data.file_checksum: errmsg = ERRMSG_INPUT_FILE_CHECKSUM_MISMATCH if type(errmsg) in types.StringTypes: self.reset_state(acting_client) return errmsg disassembly.cache_segment_data(self.disassembly_data, input_data_file) disassembly.load_project_file_finalise(self.disassembly_data) entrypoint_address = disassembly.get_entrypoint_address(self.disassembly_data) line_number = disassembly.get_line_number_for_address(self.disassembly_data, entrypoint_address) self.set_line_number(acting_client, line_number) def _pre_line_change_callback(line0, line_count): for client in self.clients: client.event_pre_line_change(client is acting_client, line0, line_count) self.disassembly_data.pre_line_change_func = _pre_line_change_callback def _post_line_change_callback(line0, line_count): for client in self.clients: client.event_post_line_change(client is acting_client, line0, line_count) self.disassembly_data.post_line_change_func = _post_line_change_callback for client in self.clients: client.event_load_successful(client is acting_client) return result
def get_line_number_for_address(self, acting_client, address): return disassembly.get_line_number_for_address(self.disassembly_data, address)
def get_source_code_for_address(self, acting_client, address): line_idx = disassembly.get_line_number_for_address(self.disassembly_data, address) return self.get_source_code_for_line_number(acting_client, line_idx)