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
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
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)
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