Ejemplo n.º 1
0
    def process_packet_info(self, hi, inst):
        """Process packet information.

        Keeping track of all the instructions in the packet is necessary as many
        instructions depend on previous ones (e.g., constant extenders), and this
        dependency is only limited to the packet: all the information needed to
        correctly disassemble the instructions is in the packet itself.

        The disassembler is designed to be used in sequential mode, disassembling
        all the instructions in the same packet one after the other. A single instruction
        can't be correctly analyzed outside that scope (although IDA analysis sometimes
        does that).

        During a packet disassembly, if an instruction from a different packet is
        disassembled (calling `disasm_one_inst`) all the current packet information
        is lost. All the instructions of a single packet have to be disassembled in
        continuous order.

        Args:
            hi (HexagonInstruction): Current instruction being disassembled.
            inst (int): Actual instruction value.

        Returns:
            None

        TODOs:
            * Review and move part of this docstring to the project documentation.

            * Remove the `inst` argument once it is added to the HexagonInstruction class.

        """

        # Check if a new packet is being disassembled, either because:
        #   1. This is the first ever instruction being disassembled (i.e.,
        #       ``curr_packet`` is None).
        #   2. The previous (contiguous) instruction was the end of its packet,
        #       therefore this instruction has to start a new one.
        #   3. The previous disassembled instruction is not contiguous (an address
        #       that is not 4 bytes back), so it has to be assumed (for lack of any
        #       other information) that a new packet is being disassembled. There
        #       is no way to know for sure that this instruction is indeed the first one
        #       in the packet (the parse bits only indicate the last, but not the
        #       first instruction), so it's the safest bet (assuming the disassembler
        #       is being correctly used a jump to the middle of tha packet is not allowed).

        if self.curr_packet is None:
            hi.start_packet = True
            # Case 1.

        elif hi.addr - INST_SIZE == self.curr_packet.get_last_inst().addr:
            # There's a continuity in the disassembler use.

            if self.curr_packet.get_last_inst().end_packet:
                hi.start_packet = True
                # Case 2.

            else:
                hi.start_packet = False
                # The current packet continues with this instruction.

        else:
            hi.start_packet = True
            # Case 3.

        if hi.start_packet:
            self.curr_packet = HexagonPacket(hi)
            # If it is the first instruction in the packet it has to be new one.

        else:
            self.curr_packet.add_next_inst(hi)
            # This instruction continues the current packet so it's added to the list.

        hi.packet = self.curr_packet
        # TODO: Maybe there's some overlapping here and I don't need `self.curr_packet`.

        # Check if this instruction is the end of the packet, which is indicated by
        # the PP (parity) bits if their value is:
        #   1. '11' for a normal instruction, signals packet end.
        #   2. '00' signals a duplex instruction, and from the manual: "The duplex
        #       must always appear as the last word in a packet."

        hi.parse_bits = extract_bits(inst, 15, 14)
        if hi.parse_bits in [0b00, 0b11]:
            hi.end_packet = True
        else:
            hi.end_packet = False
        # TODO: Perform two different checks. The normal PP == 11, and `hi.is_duplex` in
        # another if (`is_duplex` has to be set first, which is not happening now).

        return