class Disassembly: def __init__(self, snapshot, ctl_parser, final=False, defb_size=8, defb_mod=1, zfill=False, defm_width=66, asm_hex=False, asm_lower=False): self.disassembler = Disassembler(snapshot, defb_size, defb_mod, zfill, defm_width, asm_hex, asm_lower) self.ctl_parser = ctl_parser if asm_hex: if asm_lower: self.address_fmt = '{0:04x}' else: self.address_fmt = '{0:04X}' else: self.address_fmt = '{0}' self.entry_map = {} self.build(final) def build(self, final=False): self.instructions = {} self.entries = [] self._create_entries() self.org = self.entries[0].address if final: self._calculate_references() def _create_entries(self): for block in self.ctl_parser.get_blocks(): if block.start in self.entry_map: entry = self.entry_map[block.start] self.entries.append(entry) for instruction in entry.instructions: self.instructions[instruction.address] = instruction continue title = block.title if block.ctl == 'c': title = title or 'Routine at {}'.format(self._address_str(block.start)) elif block.ctl in 'bw': title = title or 'Data block at {}'.format(self._address_str(block.start)) elif block.ctl == 't': title = title or 'Message at {}'.format(self._address_str(block.start)) elif block.ctl == 'g': title = title or 'Game status buffer entry at {}'.format(self._address_str(block.start)) elif block.ctl in 'us': title = title or 'Unused' elif block.ctl == 'i' and (block.description or block.registers or block.blocks[0].header): title = title or 'Ignored' for sub_block in block.blocks: address = sub_block.start if sub_block.ctl in 'cBT': base = sub_block.sublengths[0][1] instructions = self.disassembler.disassemble(sub_block.start, sub_block.end, base) elif sub_block.ctl in 'bgstuw': sublengths = sub_block.sublengths if sublengths[0][0]: if sub_block.ctl == 's': length = sublengths[0][0] else: length = sum([s[0] for s in sublengths]) else: length = sub_block.end - sub_block.start instructions = [] while address < sub_block.end: end = min(address + length, sub_block.end) if sub_block.ctl == 't': instructions += self.disassembler.defm_range(address, end, sublengths) elif sub_block.ctl == 'w': instructions += self.disassembler.defw_range(address, end, sublengths) elif sub_block.ctl == 's': instructions.append(self.disassembler.defs(address, end, sublengths)) else: instructions += self.disassembler.defb_range(address, end, sublengths) address += length else: instructions = self.disassembler.ignore(sub_block.start, sub_block.end) sub_block.instructions = instructions for instruction in instructions: self.instructions[instruction.address] = instruction instruction.asm_directives = sub_block.asm_directives.get(instruction.address, ()) sub_blocks = [] i = 0 while i < len(block.blocks): sub_block = block.blocks[i] i += 1 sub_blocks.append(sub_block) if sub_block.multiline_comment is not None: end, sub_block.comment = sub_block.multiline_comment while i < len(block.blocks) and block.blocks[i].start < end: next_sub_block = block.blocks[i] sub_block.instructions += next_sub_block.instructions sub_block.end = next_sub_block.end i += 1 entry = Entry(title, block.description, block.ctl, sub_blocks, block.registers, block.end_comment, block.asm_directives, block.ignoreua_directives) self.entry_map[entry.address] = entry self.entries.append(entry) for i, entry in enumerate(self.entries[1:]): self.entries[i].next = entry def remove_entry(self, address): if address in self.entry_map: del self.entry_map[address] def contains_entry_asm_directive(self, asm_dir): for entry in self.entries: for directive, value in entry.asm_directives: if directive == asm_dir: return True def _calculate_references(self): for entry in self.entries: for instruction in entry.instructions: instruction.referrers = [] for entry in self.entries: for instruction in entry.instructions: operation = instruction.operation if operation.upper().startswith(('DJ', 'JR', 'JP', 'CA', 'RS')): addr_str = get_address(operation) if addr_str: callee = self.instructions.get(parse_int(addr_str)) if callee: callee.add_referrer(entry) def _address_str(self, address): return self.address_fmt.format(address)
class Disassembly: def __init__(self, snapshot, ctl_parser, config=None, final=False, defb_size=8, defb_mod=1, zfill=False, defm_width=66, asm_hex=False, asm_lower=False): ctl_parser.apply_asm_data_directives(snapshot) self.disassembler = Disassembler(snapshot, defb_size, defb_mod, zfill, defm_width, asm_hex, asm_lower) self.ctl_parser = ctl_parser if asm_hex: if asm_lower: self.address_fmt = '{0:04x}' else: self.address_fmt = '{0:04X}' else: self.address_fmt = '{0}' self.entry_map = {} self.config = config or {} self.build(final) def build(self, final=False): self.instructions = {} self.entries = [] self._create_entries() if self.entries: self.org = self.entries[0].address else: self.org = None if final: self._calculate_references() def _create_entries(self): for block in self.ctl_parser.get_blocks(): if block.start in self.entry_map: entry = self.entry_map[block.start] self.entries.append(entry) for instruction in entry.instructions: self.instructions[instruction.address] = instruction continue title = block.title if not title: ctl = block.ctl if ctl != 'i' or block.description or block.registers or block.blocks[ 0].header: name = 'Title-' + ctl title = format_template(self.config.get(name, ''), name, address=self._address_str( block.start)) for sub_block in block.blocks: address = sub_block.start if sub_block.ctl in 'cBT': base = sub_block.sublengths[0][1] instructions = self.disassembler.disassemble( sub_block.start, sub_block.end, base) elif sub_block.ctl in 'bgstuw': sublengths = sub_block.sublengths if sublengths[0][0]: if sub_block.ctl == 's': length = sublengths[0][0] else: length = sum([s[0] for s in sublengths]) else: length = sub_block.end - sub_block.start instructions = [] while address < sub_block.end: end = min(address + length, sub_block.end) if sub_block.ctl == 't': instructions += self.disassembler.defm_range( address, end, sublengths) elif sub_block.ctl == 'w': instructions += self.disassembler.defw_range( address, end, sublengths) elif sub_block.ctl == 's': instructions.append( self.disassembler.defs(address, end, sublengths)) else: instructions += self.disassembler.defb_range( address, end, sublengths) address += length else: instructions = self.disassembler.ignore( sub_block.start, sub_block.end) sub_block.instructions = instructions for instruction in instructions: self.instructions[instruction.address] = instruction instruction.asm_directives = sub_block.asm_directives.get( instruction.address, ()) sub_blocks = [] i = 0 while i < len(block.blocks): sub_block = block.blocks[i] i += 1 sub_blocks.append(sub_block) if sub_block.multiline_comment is not None: end, sub_block.comment = sub_block.multiline_comment while i < len( block.blocks) and block.blocks[i].start < end: next_sub_block = block.blocks[i] sub_block.instructions += next_sub_block.instructions sub_block.end = next_sub_block.end i += 1 entry = Entry(block.header, title, block.description, block.ctl, sub_blocks, block.registers, block.end_comment, block.footer, block.asm_directives, block.ignoreua_directives) self.entry_map[entry.address] = entry self.entries.append(entry) for i, entry in enumerate(self.entries[1:]): self.entries[i].next = entry def remove_entry(self, address): if address in self.entry_map: del self.entry_map[address] def _calculate_references(self): for entry in self.entries: for instruction in entry.instructions: instruction.referrers = [] for entry in self.entries: for instruction in entry.instructions: operation = instruction.operation if operation.upper().startswith( ('DJ', 'JR', 'JP', 'CA', 'RS')): addr_str = get_address(operation) if addr_str: callee = self.instructions.get(parse_int(addr_str)) if callee: callee.add_referrer(entry) def _address_str(self, address): return self.address_fmt.format(address)
class Disassembly: def __init__(self, snapshot, ctl_parser, config=None, final=False, defb_size=8, defb_mod=1, zfill=False, defm_width=66, asm_hex=False, asm_lower=False): ctl_parser.apply_asm_data_directives(snapshot) self.disassembler = Disassembler(snapshot, defb_size, defb_mod, zfill, defm_width, asm_hex, asm_lower) self.ctl_parser = ctl_parser if asm_hex: if asm_lower: self.address_fmt = '{0:04x}' else: self.address_fmt = '{0:04X}' else: self.address_fmt = '{0}' self.entry_map = {} self.config = config or {} self.build(final) def build(self, final=False): self.instructions = {} self.entries = [] self._create_entries() if self.entries: self.org = self.entries[0].address else: self.org = None if final: self._calculate_references() def _create_entries(self): for block in self.ctl_parser.get_blocks(): if block.start in self.entry_map: entry = self.entry_map[block.start] self.entries.append(entry) for instruction in entry.instructions: self.instructions[instruction.address] = instruction continue title = block.title if not any(title): ctl = block.ctl if ctl != 'i' or block.description or block.registers or block.blocks[0].header: name = 'Title-' + ctl title = [format_template(self.config.get(name, ''), name, address=self._address_str(block.start))] for sub_block in block.blocks: address = sub_block.start if sub_block.ctl in 'cBT': base = sub_block.sublengths[0][1] instructions = self.disassembler.disassemble(sub_block.start, sub_block.end, base) elif sub_block.ctl in 'bgstuw': sublengths = sub_block.sublengths if sublengths[0][0]: if sub_block.ctl == 's': length = sublengths[0][0] else: length = sum([s[0] for s in sublengths]) else: length = sub_block.end - sub_block.start instructions = [] while address < sub_block.end: end = min(address + length, sub_block.end) if sub_block.ctl == 't': instructions += self.disassembler.defm_range(address, end, sublengths) elif sub_block.ctl == 'w': instructions += self.disassembler.defw_range(address, end, sublengths) elif sub_block.ctl == 's': instructions += self.disassembler.defs(address, end, sublengths) else: instructions += self.disassembler.defb_range(address, end, sublengths) address += length else: instructions = self.disassembler.ignore(sub_block.start, sub_block.end) self._add_instructions(sub_block, instructions) sub_blocks = [] i = 0 while i < len(block.blocks): sub_block = block.blocks[i] i += 1 sub_blocks.append(sub_block) if sub_block.multiline_comment is not None: end, sub_block.comment = sub_block.multiline_comment while i < len(block.blocks) and block.blocks[i].start < end: next_sub_block = block.blocks[i] sub_block.instructions += next_sub_block.instructions sub_block.end = next_sub_block.end i += 1 entry = Entry(block.header, title, block.description, block.ctl, sub_blocks, block.registers, block.end_comment, block.footer, block.asm_directives, block.ignoreua_directives) self.entry_map[entry.address] = entry self.entries.append(entry) for i, entry in enumerate(self.entries[1:]): self.entries[i].next = entry def remove_entry(self, address): if address in self.entry_map: del self.entry_map[address] def _add_instructions(self, sub_block, instructions): sub_block.instructions = instructions for instruction in instructions: self.instructions[instruction.address] = instruction instruction.asm_directives = sub_block.asm_directives.get(instruction.address, ()) instruction.label = None for asm_dir in instruction.asm_directives: if asm_dir.startswith(AD_LABEL + '='): instruction.label = asm_dir[6:] if instruction.label.startswith('*'): instruction.ctl = '*' break def _calculate_references(self): for entry in self.entries: for instruction in entry.instructions: instruction.referrers = [] for entry in self.entries: for instruction in entry.instructions: operation = instruction.operation if operation.upper().startswith(('DJ', 'JR', 'JP', 'CA', 'RS')): addr_str = get_address(operation) if addr_str: callee = self.instructions.get(parse_int(addr_str)) if callee and (entry.ctl != 'u' or callee.entry == entry) and callee.label != '': callee.add_referrer(entry) def _address_str(self, address): return self.address_fmt.format(address)