Source code for microprobe.passes.symbol

# Copyright 2011-2021 IBM Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
""":mod:`microprobe.passes.symbol` module

"""

# Futures
from __future__ import absolute_import, print_function

# Built-in modules
import copy
import itertools
import random

# Third party modules

# Own modules
import microprobe.code.ins
import microprobe.passes
import microprobe.utils.distrib
from microprobe import MICROPROBE_RC
from microprobe.code.address import Address, InstructionAddress
from microprobe.code.ins import instruction_set_def_properties
from microprobe.code.var import Variable
from microprobe.exceptions import MicroprobeCodeGenerationError, \
    MicroprobeUncheckableEnvironmentWarning, MicroprobeValueError
from microprobe.target.isa.instruction import InstructionType
from microprobe.utils.asm import interpret_asm
from microprobe.utils.distrib import generate_weighted_profile, \
    weighted_choice
from microprobe.utils.logger import get_logger
from microprobe.utils.misc import RejectingDict, closest_divisor, \
    Progress

# Local modules


# Constants
LOG = get_logger(__name__)
__all__ = [
    'SetInstructionLabelByIndexPass',
    'ResolveSymbolicReferencesPass',
]

# Functions


# Classes
[docs] class SetInstructionLabelByIndexPass(microprobe.passes.Pass): """SetInstructionLabelByIndexPass pass. """
[docs] def __init__(self, label, index=-1): """ :param label: :type label: :param index: :type index: """ super(SetInstructionLabelByIndexPass, self).__init__() self._label = label self._index = index self._description = "Set the label"
def __call__(self, building_block, dummy_target): cindex = 0 for bbl in building_block.cfg.bbls: for instr in bbl.instrs: cindex = cindex + 1 if cindex == self._index: instr.set_label(self._label) return return
[docs] class ResolveSymbolicReferencesPass(microprobe.passes.Pass): """ResolveSymbolicReferencesPass pass. """
[docs] def __init__(self, strict=False, instructions=None, onlyraw=False): """ """ super(ResolveSymbolicReferencesPass, self).__init__() self._description = "Translate labels of address into values" self._labels = RejectingDict() self._strict = strict self._onlyraw = onlyraw self._instructions = [] if instructions is not None: self._instructions = instructions
def __call__(self, building_block, dummy_target): """ :param building_block: :param dummy_target: """ for instr in (elem for elem in building_block.init if elem.label is not None): self._register_label(instr) for bbl in building_block.cfg.bbls: if MICROPROBE_RC['verbose']: progress = Progress(len(bbl.instrs), "Registering labels:") for instr in (elem for elem in bbl.instrs if elem.label is not None): self._register_label(instr) if MICROPROBE_RC['verbose']: progress() for instr in (elem for elem in building_block.fini if elem.label is not None): self._register_label(instr) for instr in building_block.init: self._translate_label(instr, building_block.context) for bbl in building_block.cfg.bbls: if MICROPROBE_RC['verbose']: progress = Progress(len(bbl.instrs), "Translating labels:") for instr in bbl.instrs: self._translate_label(instr, building_block.context) if MICROPROBE_RC['verbose']: progress() for instr in building_block.fini: self._translate_label(instr, building_block.context) return [] def _register_label(self, instruction): """ :param instruction: """ if instruction.label is None: return else: self._labels[instruction.label.upper()] = instruction def _translate_label(self, instruction, context): """ :param instruction: :param context: """ if self._onlyraw and not instruction.disable_asm: return if self._instructions != []: if instruction.name not in self._instructions: return for operand in instruction.operands(): if operand.value is None: continue if not isinstance(operand.value, Address): continue address = operand.value LOG.debug( "Translating label: '%s' of instruction '%s'", address, instruction.name ) if isinstance(address, InstructionAddress): if address.target_instruction is not None: target_address = address.target_instruction.address comment = "Reference to instruction at" elif ( isinstance(address.base_address, str) and address.base_address.upper() in list(self._labels.keys()) ): target_address = self._labels[ address.base_address.upper()].address + \ address.displacement comment = "Reference to %s at" % address elif ( isinstance(address.base_address, str) and address.base_address.upper() == "CODE" ): target_address = address comment = "Reference to %s at" % address else: LOG.critical(address.base_address) LOG.critical(address) LOG.critical(list(self._labels.keys())) raise NotImplementedError if operand.type.address_relative: if (context.code_segment is not None and isinstance(context.code_segment, int)): instruction.add_comment( "%s %s" % ( comment, hex( context.code_segment + target_address.displacement ) ) ) elif context.code_segment is not None: instruction.add_comment( "%s %s+0X%X" % ( comment, context.code_segment, target_address.displacement ) ) relative_offset = target_address - instruction.address operand.set_value(relative_offset, check=self._strict) else: raise NotImplementedError elif isinstance(address.base_address, Variable) or \ address.base_address == "data": if address.base_address == "data": target_address = address else: target_address = Address( base_address=address.base_address.address, displacement=address.displacement ) if operand.type.address_relative: # Code referencing data, fix address taking into account # code and data offsets if instruction.address.base_address == "code" and \ target_address.base_address == "data" and \ context.data_segment is not None and \ context.code_segment is not None: instruction_address = Address( base_address="temp", displacement=context.code_segment + instruction.address.displacement ) data_address = Address( base_address="temp", displacement=context.data_segment + target_address.displacement ) # instruction_address = Address(base_address="data", # displacement=instruction.address.displacement) relative_offset = data_address - instruction_address try: operand.set_value(relative_offset) except MicroprobeValueError: raise MicroprobeCodeGenerationError( "Unable to codify the relative offset from " "instruction at 0x%x to data at 0x%x. " "Review the correctness of the addresses and " "change them." % (instruction_address.displacement, data_address.displacement) ) if isinstance(address.base_address, Variable): comment = "Reference to var '%s' at" \ % address.base_address.name else: comment = "Reference to data at" instruction.add_comment( "%s %s" % ( comment, hex( data_address.displacement ) ) ) else: LOG.critical(instruction.address.base_address) LOG.critical(target_address.base_address) LOG.critical(context.data_segment) LOG.critical(context.code_segment) LOG.critical(context.symbolic) LOG.critical(target_address) LOG.critical(instruction) LOG.critical(operand) raise NotImplementedError else: raise NotImplementedError else: LOG.critical( "Instr: %s Instr.Address: %s, Address: %s", instruction, instruction.address, address ) LOG.critical( "Base address: %s Type: %s", address.base_address, type(address.base_address) ) raise NotImplementedError