Exemple #1
0
    def GetSectionContent(self, options, sections):
        arch = {32: '-Mi386', 64: '-Mx86-64'}[options.bits]
        data = ''.join(test_format.ParseHex(sections['hex']))

        # TODO(shcherbina): get rid of custom prefix once
        # https://code.google.com/p/nativeclient/issues/detail?id=3631
        # is actually fixed.
        tmp = tempfile.NamedTemporaryFile(prefix='tmprdfa_',
                                          mode='wb',
                                          delete=False)
        try:
            tmp.write(data)
            tmp.close()

            objdump_proc = subprocess.Popen([
                options.objdump, '-mi386', arch, '--target=binary',
                '--disassemble-all', '--disassemble-zeroes', '--insn-width=15',
                tmp.name
            ],
                                            stdout=subprocess.PIPE)

            result = ''.join(objdump_parser.SkipHeader(objdump_proc.stdout))
            return_code = objdump_proc.wait()
            assert return_code == 0, 'error running objdump'

        finally:
            tmp.close()
            os.remove(tmp.name)

        return result
Exemple #2
0
    def GetSectionContent(self, options, hex_content):
        arch = {32: '-Mi386', 64: '-Mx86-64'}[options.bits]
        data = ''.join(test_format.ParseHex(hex_content))

        tmp = tempfile.NamedTemporaryFile(mode='wb', delete=False)
        try:
            tmp.write(data)
            tmp.close()

            objdump_proc = subprocess.Popen([
                options.objdump, '-mi386', arch, '--target=binary',
                '--disassemble-all', '--disassemble-zeroes', '--insn-width=15',
                tmp.name
            ],
                                            stdout=subprocess.PIPE)

            result = ''.join(objdump_parser.SkipHeader(objdump_proc.stdout))
            return_code = objdump_proc.wait()
            assert return_code == 0, 'error running objdump'

        finally:
            tmp.close()
            os.remove(tmp.name)

        return result
Exemple #3
0
  def DisassembleChunkWithObjdump(self, data, bitness):
    """Disassemble chunk assuming it consists of valid instructions.

    Args:
      data: raw data as python string.
      bitness: 32 or 64

    Returns:
      List of objdump_parser.Instruction tuples. If data can't be disassembled
      (either contains invalid instructions or ends in a middle of instruction)
      exception is raised.
    """
    # TODO(shcherbina):
    # Replace this shameless plug with python interface to RDFA decoder once
    # https://code.google.com/p/nativeclient/issues/detail?id=3456 is done.

    arch = {32: '-Mi386', 64: '-Mx86-64'}[bitness]

    tmp = tempfile.NamedTemporaryFile(mode='wb', delete=False)
    try:
      tmp.write(data)
      tmp.close()

      objdump_proc = subprocess.Popen(
          ['objdump',
           '-mi386', arch, '--target=binary',
           '--disassemble-all', '--disassemble-zeroes',
           '--insn-width=15',
           tmp.name],
          stdout=subprocess.PIPE)

      instructions = []
      total_bytes = 0
      for line in objdump_parser.SkipHeader(objdump_proc.stdout):
        insn = objdump_parser.ParseLine(line)
        insn = objdump_parser.CanonicalizeInstruction(insn)
        instructions.append(insn)
        total_bytes += len(insn.bytes)

      assert len(data) == total_bytes

      return_code = objdump_proc.wait()
      assert return_code == 0, 'error running objdump'

      return instructions

    finally:
      tmp.close()
      os.remove(tmp.name)
    def _CheckFile(self):
        try:
            object_file = tempfile.NamedTemporaryFile(prefix=self._file_prefix,
                                                      suffix='.o',
                                                      delete=False)
            object_file.close()
            subprocess.check_call([
                options.gas,
                '--%s' % options.bits, '--strip-local-absolute',
                self._asm_file.name, '-o', object_file.name
            ])

            objdump_proc = subprocess.Popen(
                [options.objdump, '-d', '--insn-width=15', object_file.name],
                stdout=subprocess.PIPE)

            decoder_proc = subprocess.Popen(
                [options.decoder, object_file.name], stdout=subprocess.PIPE)

            for line1, line2 in itertools.izip_longest(
                    objdump_parser.SkipHeader(objdump_proc.stdout),
                    decoder_proc.stdout,
                    fillvalue=None):

                if not LineRoughlyEqual(line1, line2):
                    print 'objdump: %r' % line1
                    print 'decoder: %r' % line2
                    raise AssertionError('%r != %r' % (line1, line2))

            return_code = objdump_proc.wait()
            assert return_code == 0

            return_code = decoder_proc.wait()
            assert return_code == 0

        finally:
            os.remove(self._asm_file.name)
            os.remove(object_file.name)
Exemple #5
0
def Disassemble(options, byte_sequences_iter):
  """Disassembles all byte sequences and returns it in old or new trie."""
  asm_file = None
  object_file = None
  old_trie_set = set()
  new_trie_set = set()
  bitness = int(options.bitness)
  try:
    file_prefix = "proof_decodes"
    asm_file = tempfile.NamedTemporaryFile(
        mode='wt',
        prefix=file_prefix,
        suffix='.s',
        delete=False)
    asm_file.write('.text\n')

    accepts = []
    for entry in byte_sequences_iter:
      byte_tuple, accept_info1, accept_info2 = entry
      accepts += [(accept_info1, accept_info2)]
      asm_file.write('  .byte %s\n' % ','.join(map(hex, map(int, byte_tuple))))
    asm_file.close()

    object_file = tempfile.NamedTemporaryFile(
        prefix=file_prefix,
        suffix='.o',
        delete=False)
    object_file.close()

    subprocess.check_call([
        options.gas,
        '--%s' % bitness,
        '--strip-local-absolute',
        asm_file.name,
        '-o', object_file.name])

    objdump_proc = subprocess.Popen(
        [options.objdump, '-d', '--insn-width=15', object_file.name],
        stdout=subprocess.PIPE)

    for line, (accept_info1, accept_info2) in itertools.izip(
        objdump_parser.SkipHeader(objdump_proc.stdout),
        iter(accepts)):
      instruction = objdump_parser.CanonicalizeInstruction(
            objdump_parser.ParseLine(line),
            simplify_condition_jumps=True)
      prefixes, mnemonic, operands = (spec.ParseInstruction(instruction))
      full_operands = tuple(prefixes + [mnemonic] + operands)
      if accept_info1 is not None:
        input_rr, output_rr = GetRRInfoFromTrie(accept_info1, bitness)
        old_trie_set.add(Operands(disasms=full_operands,
                                  input_rr=input_rr,
                                  output_rr=output_rr))
      if accept_info2 is not None:
        input_rr, output_rr = GetRRInfoFromTrie(accept_info2, bitness)
        new_trie_set.add(Operands(disasms=full_operands,
                                  input_rr=input_rr,
                                  output_rr=output_rr))

    return_code = objdump_proc.wait()
    assert return_code == 0

  finally:
    os.remove(asm_file.name)
    os.remove(object_file.name)

  return old_trie_set, new_trie_set
def ProcessSuperinstructionsFile(filename, bitness, gas, objdump, out_file):
  """Process superinstructions file.

  Each line produces either "True" or "False" plus text of original command
  (for the documentation purposes).  "True" means instruction is safe, "False"
  means instruction is unsafe.  This is needed since some instructions are
  incorrect but accepted by DFA (these should be rejected by actions embedded
  in DFA).

  If line contains something except valid set of x86 instruction assert
  error is triggered.

  Args:
      filename: name of file to process
      bitness: 32 or 64
      gas: path to the GAS executable
      objdump: path to the OBJDUMP executable
  Returns:
      None
  """

  try:
    object_file = tempfile.NamedTemporaryFile(
        prefix='verify_superinstructions_',
        suffix='.o',
        delete=False)
    object_file.close()

    subprocess.check_call([gas,
                           '--{0}'.format(bitness),
                           filename,
                           '-o{0}'.format(object_file.name)])

    objdump_proc = subprocess.Popen(
        [objdump, '-d', object_file.name, '--insn-width=15'],
        stdout=subprocess.PIPE)

    objdump_iter = iter(objdump_parser.SkipHeader(objdump_proc.stdout))

    line_prefix = '.byte '

    with open(filename) as superinstructions:
      for superinstruction_line in superinstructions:
        # Split the source line to find bytes
        assert superinstruction_line.startswith(line_prefix)
        # Leave only bytes here
        bytes_only = superinstruction_line[len(line_prefix):]
        superinstruction_bytes = [byte.strip(' \n')
                                  for byte in bytes_only.split(',')]
        superinstruction_validated = ValidateSuperinstruction(
            bytearray([int(byte, 16) for byte in superinstruction_bytes]),
            bitness)
        # Pick disassembled form of the superinstruction from objdump output
        superinstruction = []
        objdump_bytes = []
        while len(objdump_bytes) < len(superinstruction_bytes):
          nextline = next(objdump_iter).decode()
          instruction = objdump_parser.ParseLine(nextline)
          instruction = objdump_parser.CanonicalizeInstruction(instruction)
          superinstruction.append(instruction)
          objdump_bytes += instruction.bytes
        # Bytes in objdump output in and source file should match
        assert ['0x%02x' % b for b in objdump_bytes] == superinstruction_bytes
        if bitness == 32:
          validate_superinstruction = spec.ValidateSuperinstruction32
        else:
          validate_superinstruction = spec.ValidateSuperinstruction64

        try:
          validate_superinstruction(superinstruction)
          assert superinstruction_validated, (
              'validator rejected superinstruction allowed by spec',
              superinstruction)
        except spec.SandboxingError as e:
          assert not superinstruction_validated, (
              'validator allowed superinstruction rejected by spec',
              superinstruction,
              e)
        except spec.DoNotMatchError:
          raise
  finally:
    os.remove(object_file.name)
  def CheckReceivedInstructions(self):
    # Check instructions accumulated so far and clear the list.
    if len(self._instructions) == 0:
      return
    try:
      raw_file = tempfile.NamedTemporaryFile(
          mode='wb',
          prefix=self._file_prefix,
          suffix='.o',
          delete=False)
      for instr in self._instructions:
        raw_file.write(''.join(map(chr, instr)))
      raw_file.close()

      objdump_proc = subprocess.Popen(
          [options.objdump,
           '-D',
           '-b', 'binary',
           '-m', 'i386'] +
          {32: [], 64: ['-M', 'x86-64']}[options.bitness] +
          ['--insn-width', '15',
           raw_file.name],
          stdout=subprocess.PIPE)

      objdump_iter = iter(objdump_parser.SkipHeader(objdump_proc.stdout))

      old_validator = OldValidator()
      for instr in self._instructions:
        # Objdump prints fwait with REX prefix in this ridiculous way:
        #   0: 41    fwait
        #   1: 9b    fwait
        # So in such cases we expect two lines from objdump.
        # TODO(shcherbina): get rid of this special handling once
        # https://code.google.com/p/nativeclient/issues/detail?id=3496 is fixed.
        if len(instr) == 2 and IsRexPrefix(instr[0]) and instr[1] == FWAIT:
          expected_lines = 2
        else:
          expected_lines = 1

        bytes = []
        for _ in range(expected_lines):
          line = next(objdump_iter)
          # Parse tab-separated line of the form
          # 0:  f2 40 0f 10 00        rex movsd (%rax),%xmm0
          addr, more_bytes, disassembly = line.strip().split('\t')
          more_bytes = [int(b, 16) for b in more_bytes.split()]
          bytes += more_bytes

        assert bytes == instr, (map(hex, bytes), map(hex, instr))
        self.total_instructions += 1

        self.num_valid += ValidateInstruction(instr, disassembly, old_validator)

      # Make sure we read objdump output to the end.
      end = next(objdump_iter, None)
      assert end is None, end

      return_code = objdump_proc.wait()
      assert return_code == 0

    finally:
      os.remove(raw_file.name)

    errors = old_validator.GetErrors()
    for error in errors:
      print error
    self.errors += errors