def __init__(self, constraints, address, data, caller, value, bytecode, world=None, gas=<NUM_LIT>, **kwargs):

super().__init__(**kwargs)<EOL>if data is not None and not issymbolic(data):<EOL><INDENT>data_size = len(data)<EOL>data_symbolic = constraints.new_array(index_bits=<NUM_LIT>, value_bits=<NUM_LIT:8>, index_max=data_size, name=f'<STR_LIT>', avoid_collisions=True, default=<NUM_LIT:0>)<EOL>data_symbolic[<NUM_LIT:0>:data_size] = data<EOL>data = data_symbolic<EOL><DEDENT>if bytecode is not None and not issymbolic(bytecode):<EOL><INDENT>bytecode_size = len(bytecode)<EOL>bytecode_symbolic = constraints.new_array(index_bits=<NUM_LIT>, value_bits=<NUM_LIT:8>, index_max=bytecode_size, name=f'<STR_LIT>', avoid_collisions=True, default=<NUM_LIT:0>)<EOL>bytecode_symbolic[<NUM_LIT:0>:bytecode_size] = bytecode<EOL>bytecode = bytecode_symbolic<EOL><DEDENT>self._check_jumpdest = False<EOL>self._valid_jumpdests = set()<EOL>def extend_with_zeroes(b):<EOL><INDENT>try:<EOL><INDENT>for x in b:<EOL><INDENT>x = to_constant(x)<EOL>if isinstance(x, int):<EOL><INDENT>yield(x)<EOL><DEDENT>else:<EOL><INDENT>yield(<NUM_LIT:0>)<EOL><DEDENT><DEDENT>for _ in range(<NUM_LIT:32>):<EOL><INDENT>yield(<NUM_LIT:0>)<EOL><DEDENT><DEDENT>except Exception as e:<EOL><INDENT>return<EOL><DEDENT><DEDENT>for i in EVMAsm.disassemble_all(extend_with_zeroes(bytecode)):<EOL><INDENT>if i.mnemonic == '<STR_LIT>':<EOL><INDENT>self._valid_jumpdests.add(i.pc)<EOL><DEDENT><DEDENT>self._constraints = constraints<EOL>self.memory = constraints.new_array(index_bits=<NUM_LIT>, value_bits=<NUM_LIT:8>, name=f'<STR_LIT>', avoid_collisions=True, default=<NUM_LIT:0>)<EOL>self.address = address<EOL>self.caller = caller  <EOL>self.data = data<EOL>self.value = value<EOL>self._bytecode = bytecode<EOL>self.suicides = set()<EOL>self.logs = []<EOL>self.pc = <NUM_LIT:0><EOL>self.stack = []<EOL>self._gas = Operators.ZEXTEND(gas, <NUM_LIT>)<EOL>self._world = world<EOL>self._allocated = <NUM_LIT:0><EOL>self._on_transaction = False  <EOL>self._checkpoint_data = None<EOL>self._published_pre_instruction_events = False<EOL>min_size = <NUM_LIT:0><EOL>max_size = len(self.data)<EOL>self._used_calldata_size = <NUM_LIT:0><EOL>self._calldata_size = len(self.data)<EOL>self._valid_jmpdests = set()<EOL>

Builds a Ethereum Virtual Machine instance

:param memory: the initial memory
:param address: the address of the account which owns the code that is executing.
:param data: the byte array that is the input data to this execution
:param caller: the address of the account which caused the code to be executing. A 160-bit code used for identifying Accounts
:param value: the value, in Wei, passed to this account as part of the same procedure as execution. One Ether is defined as being 10**18 Wei
:param bytecode: the byte array that is the machine code to be executed
:param world: the EVMWorld object where the transaction is being executed
:param gas: gas budget for this transaction


def _get_memfee(self, address, size=<NUM_LIT:1>):

if not issymbolic(size) and size == <NUM_LIT:0>:<EOL><INDENT>return <NUM_LIT:0><EOL><DEDENT>address = self.safe_add(address, size)<EOL>allocated = self.allocated<EOL>GMEMORY = <NUM_LIT:3><EOL>GQUADRATICMEMDENOM = <NUM_LIT>  <EOL>old_size = Operators.ZEXTEND(Operators.UDIV(self.safe_add(allocated, <NUM_LIT>), <NUM_LIT:32>), <NUM_LIT>)<EOL>new_size = Operators.ZEXTEND(Operators.UDIV(self.safe_add(address, <NUM_LIT>), <NUM_LIT:32>), <NUM_LIT>)<EOL>old_totalfee = self.safe_mul(old_size, GMEMORY) + Operators.UDIV(self.safe_mul(old_size, old_size), GQUADRATICMEMDENOM)<EOL>new_totalfee = self.safe_mul(new_size, GMEMORY) + Operators.UDIV(self.safe_mul(new_size, new_size), GQUADRATICMEMDENOM)<EOL>memfee = new_totalfee - old_totalfee<EOL>flag = Operators.UGT(new_totalfee, old_totalfee)<EOL>return Operators.ITEBV(<NUM_LIT>, size == <NUM_LIT:0>, <NUM_LIT:0>, Operators.ITEBV(<NUM_LIT>, flag, memfee, <NUM_LIT:0>))<EOL>

This calculates the amount of extra gas needed for accessing to
previously unused memory.

:param address: base memory offset
:param size: size of the memory access


def read_code(self, address, size=<NUM_LIT:1>):

assert address < len(self.bytecode)<EOL>value = self.bytecode[address:address + size]<EOL>if len(value) < size:<EOL><INDENT>value += '<STR_LIT:\x00>' * (size - len(value))  <EOL><DEDENT>return value<EOL>

Read size byte from bytecode.
If less than size bytes are available result will be pad with \x00


<EOL>try:<EOL><INDENT>_decoding_cache = getattr(self, '<STR_LIT>')<EOL><DEDENT>except Exception:<EOL><INDENT>_decoding_cache = self._decoding_cache = {}<EOL><DEDENT>pc = self.pc<EOL>if isinstance(pc, Constant):<EOL><INDENT>pc = pc.value<EOL><DEDENT>if pc in _decoding_cache:<EOL><INDENT>return _decoding_cache[pc]<EOL><DEDENT>def getcode():<EOL><INDENT>bytecode = self.bytecode<EOL>for pc_i in range(pc, len(bytecode)):<EOL><INDENT>yield simplify(bytecode[pc_i]).value<EOL><DEDENT>while True:<EOL><INDENT>yield <NUM_LIT:0><EOL><DEDENT><DEDENT>instruction = EVMAsm.disassemble_one(getcode(), pc=pc, fork=DEFAULT_FORK)<EOL>_decoding_cache[pc] = instruction<EOL>return instruction<EOL>


assert isinstance(value, int) or isinstance(value, BitVec) and value.size == <NUM_LIT><EOL>if len(self.stack) >= <NUM_LIT>:<EOL><INDENT>raise StackOverflow()<EOL><DEDENT>if isinstance(value, int):<EOL><INDENT>value = value & TT256M1<EOL><DEDENT>value = simplify(value)<EOL>if isinstance(value, Constant) and not value.taint:<EOL><INDENT>value = value.value<EOL><DEDENT>self.stack.append(value)<EOL>

Push into the stack

      ITEM0
      ITEM1
      ITEM2
sp->  {empty}


if len(self.stack) - n < <NUM_LIT:0>:<EOL><INDENT>raise StackUnderflow()<EOL><DEDENT>return self.stack[n - <NUM_LIT:1>]<EOL>

Read a value from the top of the stack without removing it


if len(self.stack) == <NUM_LIT:0>:<EOL><INDENT>raise StackUnderflow()<EOL><DEDENT>return self.stack.pop()<EOL>


<EOL>if self._checkpoint_data is None:<EOL><INDENT>if not self._published_pre_instruction_events:<EOL><INDENT>self._published_pre_instruction_events = True<EOL>self._publish('<STR_LIT>', self.pc)<EOL>self._publish('<STR_LIT>', self.pc, self.instruction)<EOL>self._publish('<STR_LIT>', self.instruction, self._top_arguments())<EOL><DEDENT>pc = self.pc<EOL>instruction = self.instruction<EOL>old_gas = self.gas<EOL>allocated = self._allocated<EOL>arguments = self._pop_arguments()<EOL>fee = self._calculate_gas(*arguments)<EOL>self._checkpoint_data = (pc, old_gas, instruction, arguments, fee, allocated)<EOL><DEDENT>return self._checkpoint_data<EOL>

Save and/or get a state checkpoint previous to current instruction


last_pc, last_gas, last_instruction, last_arguments, fee, allocated = self._checkpoint_data<EOL>self._push_arguments(last_arguments)<EOL>self._gas = last_gas<EOL>self._pc = last_pc<EOL>self._allocated = allocated<EOL>self._checkpoint_data = None<EOL>

Revert the stack, gas, pc and memory allocation so it looks like before executing the instruction


self._check_jumpdest = flag<EOL>

Next instruction must be a JUMPDEST iff `flag` holds.

Note that at this point `flag` can be the conditional from a JUMPI
instruction hence potentially a symbolic value.


should_check_jumpdest = self._check_jumpdest<EOL>if issymbolic(should_check_jumpdest):<EOL><INDENT>should_check_jumpdest_solutions = solver.get_all_values(self.constraints, should_check_jumpdest)<EOL>if len(should_check_jumpdest_solutions) != <NUM_LIT:1>:<EOL><INDENT>raise EthereumError("<STR_LIT>")<EOL><DEDENT>should_check_jumpdest = should_check_jumpdest_solutions[<NUM_LIT:0>]<EOL><DEDENT>if should_check_jumpdest:<EOL><INDENT>self._check_jumpdest = False<EOL>pc = self.pc.value if isinstance(self.pc, Constant) else self.pc<EOL>if pc not in self._valid_jumpdests:<EOL><INDENT>raise InvalidOpcode()<EOL><DEDENT><DEDENT>

If the previous instruction was a JUMP/JUMPI and the conditional was
True, this checks that the current instruction must be a JUMPDEST.

Here, if symbolic, the conditional `self._check_jumpdest` would be
already constrained to a single concrete value.


def _store(self, offset, value, size=<NUM_LIT:1>):

self.memory.write_BE(offset, value, size)<EOL>for i in range(size):<EOL><INDENT>self._publish('<STR_LIT>', offset + i, Operators.EXTRACT(value, (size - i - <NUM_LIT:1>) * <NUM_LIT:8>, <NUM_LIT:8>))<EOL><DEDENT>


raise InvalidOpcode()<EOL>


raise EndTx('<STR_LIT>')<EOL>


return a + b<EOL>


return a * b<EOL>


return a - b<EOL>


try:<EOL><INDENT>result = Operators.UDIV(a, b)<EOL><DEDENT>except ZeroDivisionError:<EOL><INDENT>result = <NUM_LIT:0><EOL><DEDENT>return Operators.ITEBV(<NUM_LIT>, b == <NUM_LIT:0>, <NUM_LIT:0>, result)<EOL>


s0, s1 = to_signed(a), to_signed(b)<EOL>try:<EOL><INDENT>result = (Operators.ABS(s0) // Operators.ABS(s1) * Operators.ITEBV(<NUM_LIT>, (s0 < <NUM_LIT:0>) != (s1 < <NUM_LIT:0>), -<NUM_LIT:1>, <NUM_LIT:1>))<EOL><DEDENT>except ZeroDivisionError:<EOL><INDENT>result = <NUM_LIT:0><EOL><DEDENT>result = Operators.ITEBV(<NUM_LIT>, b == <NUM_LIT:0>, <NUM_LIT:0>, result)<EOL>if not issymbolic(result):<EOL><INDENT>result = to_signed(result)<EOL><DEDENT>return result<EOL>

Signed integer division operation (truncated)


try:<EOL><INDENT>result = Operators.ITEBV(<NUM_LIT>, b == <NUM_LIT:0>, <NUM_LIT:0>, a % b)<EOL><DEDENT>except ZeroDivisionError:<EOL><INDENT>result = <NUM_LIT:0><EOL><DEDENT>return result<EOL>


s0, s1 = to_signed(a), to_signed(b)<EOL>sign = Operators.ITEBV(<NUM_LIT>, s0 < <NUM_LIT:0>, -<NUM_LIT:1>, <NUM_LIT:1>)<EOL>try:<EOL><INDENT>result = (Operators.ABS(s0) % Operators.ABS(s1)) * sign<EOL><DEDENT>except ZeroDivisionError:<EOL><INDENT>result = <NUM_LIT:0><EOL><DEDENT>return Operators.ITEBV(<NUM_LIT>, s1 == <NUM_LIT:0>, <NUM_LIT:0>, result)<EOL>


try:<EOL><INDENT>result = Operators.ITEBV(<NUM_LIT>, c == <NUM_LIT:0>, <NUM_LIT:0>, (a + b) % c)<EOL><DEDENT>except ZeroDivisionError:<EOL><INDENT>result = <NUM_LIT:0><EOL><DEDENT>return result<EOL>


try:<EOL><INDENT>result = Operators.ITEBV(<NUM_LIT>, c == <NUM_LIT:0>, <NUM_LIT:0>, (a * b) % c)<EOL><DEDENT>except ZeroDivisionError:<EOL><INDENT>result = <NUM_LIT:0><EOL><DEDENT>return result<EOL>


EXP_SUPPLEMENTAL_GAS = <NUM_LIT:10>   <EOL>def nbytes(e):<EOL><INDENT>result = <NUM_LIT:0><EOL>for i in range(<NUM_LIT:32>):<EOL><INDENT>result = Operators.ITEBV(<NUM_LIT>, Operators.EXTRACT(e, i * <NUM_LIT:8>, <NUM_LIT:8>) != <NUM_LIT:0>, i + <NUM_LIT:1>, result)<EOL><DEDENT>return result<EOL><DEDENT>return EXP_SUPPLEMENTAL_GAS * nbytes(exponent)<EOL>


<EOL>return pow(base, exponent, TT256)<EOL>

Exponential operation
The zero-th power of zero 0^0 is defined to be one


<EOL>testbit = Operators.ITEBV(<NUM_LIT>, size <= <NUM_LIT>, size * <NUM_LIT:8> + <NUM_LIT:7>, <NUM_LIT>)<EOL>result1 = (value | (TT256 - (<NUM_LIT:1> << testbit)))<EOL>result2 = (value & ((<NUM_LIT:1> << testbit) - <NUM_LIT:1>))<EOL>result = Operators.ITEBV(<NUM_LIT>, (value & (<NUM_LIT:1> << testbit)) != <NUM_LIT:0>, result1, result2)<EOL>return Operators.ITEBV(<NUM_LIT>, size <= <NUM_LIT>, result, value)<EOL>

Extend length of two's complement signed integer


return Operators.ITEBV(<NUM_LIT>, Operators.ULT(a, b), <NUM_LIT:1>, <NUM_LIT:0>)<EOL>


return Operators.ITEBV(<NUM_LIT>, Operators.UGT(a, b), <NUM_LIT:1>, <NUM_LIT:0>)<EOL>


<EOL>s0, s1 = to_signed(a), to_signed(b)<EOL>return Operators.ITEBV(<NUM_LIT>, s0 < s1, <NUM_LIT:1>, <NUM_LIT:0>)<EOL>


<EOL>s0, s1 = to_signed(a), to_signed(b)<EOL>return Operators.ITEBV(<NUM_LIT>, s0 > s1, <NUM_LIT:1>, <NUM_LIT:0>)<EOL>


return Operators.ITEBV(<NUM_LIT>, a == b, <NUM_LIT:1>, <NUM_LIT:0>)<EOL>


return Operators.ITEBV(<NUM_LIT>, a == <NUM_LIT:0>, <NUM_LIT:1>, <NUM_LIT:0>)<EOL>


return a & b<EOL>


return a | b<EOL>


return a ^ b<EOL>


return ~a<EOL>


offset = Operators.ITEBV(<NUM_LIT>, offset < <NUM_LIT:32>, (<NUM_LIT> - offset) * <NUM_LIT:8>, <NUM_LIT>)<EOL>return Operators.ZEXTEND(Operators.EXTRACT(value, offset, <NUM_LIT:8>), <NUM_LIT>)<EOL>


@concretized_args(size='<STR_LIT>')<EOL><INDENT>def SHA3(self, start, size):<DEDENT>

<EOL>data = self.try_simplify_to_constant(self.read_buffer(start, size))<EOL>if issymbolic(data):<EOL><INDENT>known_sha3 = {}<EOL>self._publish('<STR_LIT>', data, known_sha3)  <EOL>value = <NUM_LIT:0>  <EOL>known_hashes_cond = False<EOL>for key, hsh in known_sha3.items():<EOL><INDENT>assert not issymbolic(key), "<STR_LIT>"<EOL>cond = key == data<EOL>known_hashes_cond = Operators.OR(cond, known_hashes_cond)<EOL>value = Operators.ITEBV(<NUM_LIT>, cond, hsh, value)<EOL><DEDENT>return value<EOL><DEDENT>value = sha3.keccak_256(data).hexdigest()<EOL>value = int(value, <NUM_LIT:16>)<EOL>self._publish('<STR_LIT>', data, value)<EOL>logger.info("<STR_LIT>", data, value)<EOL>return value<EOL>


return self.address<EOL>

Get address of currently executing account


return self.world.get_balance(account)<EOL>


return Operators.ZEXTEND(self.world.tx_origin(), <NUM_LIT>)<EOL>


return Operators.ZEXTEND(self.caller, <NUM_LIT>)<EOL>


return self.value<EOL>

Get deposited value by the instruction/transaction responsible for this execution


if issymbolic(offset):<EOL><INDENT>if solver.can_be_true(self._constraints, offset == self._used_calldata_size):<EOL><INDENT>self.constraints.add(offset == self._used_calldata_size)<EOL><DEDENT>raise ConcretizeArgument(<NUM_LIT:1>, policy='<STR_LIT>')<EOL><DEDENT>self._use_calldata(offset, <NUM_LIT:32>)<EOL>data_length = len(self.data)<EOL>bytes = []<EOL>for i in range(<NUM_LIT:32>):<EOL><INDENT>try:<EOL><INDENT>c = Operators.ITEBV(<NUM_LIT:8>, offset + i < data_length, self.data[offset + i], <NUM_LIT:0>)<EOL><DEDENT>except IndexError:<EOL><INDENT>c = <NUM_LIT:0><EOL><DEDENT>bytes.append(c)<EOL><DEDENT>return Operators.CONCAT(<NUM_LIT>, *bytes)<EOL>


return self._calldata_size<EOL>

Get size of input data in current environment


def CALLDATACOPY(self, mem_offset, data_offset, size):

if issymbolic(size):<EOL><INDENT>if solver.can_be_true(self._constraints, size <= len(self.data) + <NUM_LIT:32>):<EOL><INDENT>self.constraints.add(size <= len(self.data) + <NUM_LIT:32>)<EOL><DEDENT>raise ConcretizeArgument(<NUM_LIT:3>, policy='<STR_LIT>')<EOL><DEDENT>if issymbolic(data_offset):<EOL><INDENT>if solver.can_be_true(self._constraints, data_offset == self._used_calldata_size):<EOL><INDENT>self.constraints.add(data_offset == self._used_calldata_size)<EOL><DEDENT>raise ConcretizeArgument(<NUM_LIT:2>, policy='<STR_LIT>')<EOL><DEDENT>self._use_calldata(data_offset, size)<EOL>self._allocate(mem_offset, size)<EOL>for i in range(size):<EOL><INDENT>try:<EOL><INDENT>c = Operators.ITEBV(<NUM_LIT:8>, data_offset + i < len(self.data), Operators.ORD(self.data[data_offset + i]), <NUM_LIT:0>)<EOL><DEDENT>except IndexError:<EOL><INDENT>c = <NUM_LIT:0><EOL><DEDENT>self._store(mem_offset + i, c)<EOL><DEDENT>

Copy input data in current environment to memory


return len(self.bytecode)<EOL>

Get size of code running in current environment


@concretized_args(code_offset='<STR_LIT>', size='<STR_LIT>')<EOL><INDENT>def CODECOPY(self, mem_offset, code_offset, size):<DEDENT>

self._allocate(mem_offset, size)<EOL>GCOPY = <NUM_LIT:3>             <EOL>copyfee = self.safe_mul(GCOPY, Operators.UDIV(self.safe_add(size, <NUM_LIT>), <NUM_LIT:32>))<EOL>self._consume(copyfee)<EOL>if issymbolic(size):<EOL><INDENT>max_size = solver.max(self.constraints, size)<EOL><DEDENT>else:<EOL><INDENT>max_size = size<EOL><DEDENT>for i in range(max_size):<EOL><INDENT>if issymbolic(i < size):<EOL><INDENT>default = Operators.ITEBV(<NUM_LIT:8>, i < size, <NUM_LIT:0>, self._load(mem_offset + i, <NUM_LIT:1>))  <EOL><DEDENT>else:<EOL><INDENT>if i < size:<EOL><INDENT>default = <NUM_LIT:0><EOL><DEDENT>else:<EOL><INDENT>default = self._load(mem_offset + i, <NUM_LIT:1>)<EOL><DEDENT><DEDENT>if issymbolic(code_offset):<EOL><INDENT>value = Operators.ITEBV(<NUM_LIT:8>, code_offset + i >= len(self.bytecode), default, self.bytecode[code_offset + i])<EOL><DEDENT>else:<EOL><INDENT>if code_offset + i >= len(self.bytecode):<EOL><INDENT>value = default<EOL><DEDENT>else:<EOL><INDENT>value = self.bytecode[code_offset + i]<EOL><DEDENT><DEDENT>self._store(mem_offset + i, value)<EOL><DEDENT>self._publish('<STR_LIT>', code_offset, size)<EOL>

Copy code running in current environment to memory


return self.world.tx_gasprice()<EOL>


return len(self.world.get_code(account))<EOL>


@concretized_args(account='<STR_LIT>')<EOL><INDENT>def EXTCODECOPY(self, account, address, offset, size):<DEDENT>

extbytecode = self.world.get_code(account)<EOL>self._allocate(address + size)<EOL>for i in range(size):<EOL><INDENT>if offset + i < len(extbytecode):<EOL><INDENT>self._store(address + i, extbytecode[offset + i])<EOL><DEDENT>else:<EOL><INDENT>self._store(address + i, <NUM_LIT:0>)<EOL><DEDENT><DEDENT>


return self.world.block_hash(a)<EOL>

Get the hash of one of the 256 most recent complete blocks


return self.world.block_coinbase()<EOL>


return self.world.block_timestamp()<EOL>


return self.world.block_number()<EOL>


return self.world.block_difficulty()<EOL>


return self.world.block_gaslimit()<EOL>


<EOL>pass<EOL>


self._allocate(address, <NUM_LIT:32>)<EOL>value = self._load(address, <NUM_LIT:32>)<EOL>return value<EOL>


if istainted(self.pc):<EOL><INDENT>for taint in get_taints(self.pc):<EOL><INDENT>value = taint_with(value, taint)<EOL><DEDENT><DEDENT>self._allocate(address, <NUM_LIT:32>)<EOL>self._store(address, value, <NUM_LIT:32>)<EOL>


if istainted(self.pc):<EOL><INDENT>for taint in get_taints(self.pc):<EOL><INDENT>value = taint_with(value, taint)<EOL><DEDENT><DEDENT>self._allocate(address, <NUM_LIT:1>)<EOL>self._store(address, Operators.EXTRACT(value, <NUM_LIT:0>, <NUM_LIT:8>), <NUM_LIT:1>)<EOL>


storage_address = self.address<EOL>self._publish('<STR_LIT>', storage_address, offset)<EOL>value = self.world.get_storage_data(storage_address, offset)<EOL>self._publish('<STR_LIT>', storage_address, offset, value)<EOL>return value<EOL>


storage_address = self.address<EOL>self._publish('<STR_LIT>', storage_address, offset, value)<EOL>if istainted(self.pc):<EOL><INDENT>for taint in get_taints(self.pc):<EOL><INDENT>value = taint_with(value, taint)<EOL><DEDENT><DEDENT>self.world.set_storage_data(storage_address, offset, value)<EOL>self._publish('<STR_LIT>', storage_address, offset, value)<EOL>


self.pc = dest<EOL>self._set_check_jmpdest()<EOL>


self.pc = Operators.ITEBV(<NUM_LIT>, cond != <NUM_LIT:0>, dest, self.pc + self.instruction.size)<EOL>self._set_check_jmpdest(cond != <NUM_LIT:0>)<EOL>


return self.pc<EOL>

Get the value of the program counter prior to the increment


return self._allocated<EOL>


<EOL>return Operators.EXTRACT(self._gas, <NUM_LIT:0>, <NUM_LIT>)<EOL>

Get the amount of available gas, including the corresponding reduction the amount of available gas


return value<EOL>


return (operands[-<NUM_LIT:1>],) + operands<EOL>


a = operands[<NUM_LIT:0>]<EOL>b = operands[-<NUM_LIT:1>]<EOL>return (b,) + operands[<NUM_LIT:1>:-<NUM_LIT:1>] + (a,)<EOL>


@transact<EOL><INDENT>def CREATE(self, value, offset, size):<DEDENT>

Create a new account with associated code


@CREATE.pos<EOL><INDENT>def CREATE(self, value, offset, size):<DEDENT>

tx = self.world.last_transaction  <EOL>address = tx.address<EOL>if tx.result == '<STR_LIT>':<EOL><INDENT>self.world.set_code(tx.address, tx.return_data)<EOL><DEDENT>else:<EOL><INDENT>self.world.delete_account(address)<EOL>address = <NUM_LIT:0><EOL><DEDENT>return address<EOL>


@transact<EOL><INDENT>@concretized_args(address='<STR_LIT>', gas='<STR_LIT>', in_offset='<STR_LIT>', in_size='<STR_LIT>')<EOL>def CALL(self, gas, address, value, in_offset, in_size, out_offset, out_size):<DEDENT>

self.world.start_transaction('<STR_LIT>',<EOL>address,<EOL>data=self.read_buffer(in_offset, in_size),<EOL>caller=self.address,<EOL>value=value,<EOL>gas=gas)<EOL>raise StartTx()<EOL>


@transact<EOL><INDENT>@concretized_args(in_offset='<STR_LIT>', in_size='<STR_LIT>')<EOL>def CALLCODE(self, gas, _ignored_, value, in_offset, in_size, out_offset, out_size):<DEDENT>

self.world.start_transaction('<STR_LIT>',<EOL>address=self.address,<EOL>data=self.read_buffer(in_offset, in_size),<EOL>caller=self.address,<EOL>value=value,<EOL>gas=gas)<EOL>raise StartTx()<EOL>

Message-call into this account with alternative account's code


@concretized_args(size='<STR_LIT>')<EOL><INDENT>def RETURN(self, offset, size):<DEDENT>

data = self.read_buffer(offset, size)<EOL>raise EndTx('<STR_LIT>', data)<EOL>


@transact<EOL><INDENT>@concretized_args(in_offset='<STR_LIT>', in_size='<STR_LIT>')<EOL>def DELEGATECALL(self, gas, address, in_offset, in_size, out_offset, out_size):<DEDENT>

self.world.start_transaction('<STR_LIT>',<EOL>address,<EOL>data=self.read_buffer(in_offset, in_size),<EOL>caller=self.address,<EOL>value=<NUM_LIT:0>,<EOL>gas=gas)<EOL>raise StartTx()<EOL>


@transact<EOL><INDENT>@concretized_args(in_offset='<STR_LIT>', in_size='<STR_LIT>')<EOL>def STATICCALL(self, gas, address, in_offset, in_size, out_offset, out_size):<DEDENT>


<EOL>recipient = Operators.EXTRACT(recipient, <NUM_LIT:0>, <NUM_LIT>)<EOL>address = self.address<EOL>if issymbolic(recipient):<EOL><INDENT>logger.info("<STR_LIT>")<EOL>recipient = solver.get_value(self.constraints, recipient)<EOL><DEDENT>if recipient not in self.world:<EOL><INDENT>self.world.create_account(address=recipient)<EOL><DEDENT>self.world.send_funds(address, recipient, self.world.get_balance(address))<EOL>self.world.delete_account(address)<EOL>raise EndTx('<STR_LIT>')<EOL>

Halt execution and register account for later deletion


return tuple((tx for tx in self._transactions if tx.result != '<STR_LIT>'))<EOL>


txs = []<EOL>for tx in self.transactions:<EOL><INDENT>if tx.depth == <NUM_LIT:0>:<EOL><INDENT>txs.append(tx)<EOL><DEDENT><DEDENT>return tuple(txs)<EOL>


if len(self.transactions):<EOL><INDENT>return self.transactions[-<NUM_LIT:1>]<EOL><DEDENT>return None<EOL>


for tx in reversed(self.transactions):<EOL><INDENT>if tx.depth == <NUM_LIT:0>:<EOL><INDENT>return tx<EOL><DEDENT><DEDENT>return None<EOL>


try:<EOL><INDENT>_, _, _, _, vm = self._callstack[-<NUM_LIT:1>]<EOL>return vm<EOL><DEDENT>except IndexError:<EOL><INDENT>return None<EOL><DEDENT>


try:<EOL><INDENT>tx, _, _, _, _ = self._callstack[-<NUM_LIT:1>]<EOL>if tx.result is not None:<EOL><INDENT>return None<EOL><DEDENT>return tx<EOL><DEDENT>except IndexError:<EOL><INDENT>return None<EOL><DEDENT>


try:<EOL><INDENT>tx, _, _, _, _ = self._callstack[<NUM_LIT:0>]<EOL>if tx.result is not None:<EOL><INDENT>return None<EOL><DEDENT>assert tx.depth == <NUM_LIT:0><EOL>return tx<EOL><DEDENT>except IndexError:<EOL><INDENT>return None<EOL><DEDENT>


def get_storage_data(self, storage_address, offset):

value = self._world_state[storage_address]['<STR_LIT>'].get(offset, <NUM_LIT:0>)<EOL>return simplify(value)<EOL>

Read a value from a storage slot on the specified account

:param storage_address: an account address
:param offset: the storage slot to use.
:type offset: int or BitVec
:return: the value
:rtype: int or BitVec


def set_storage_data(self, storage_address, offset, value):

self._world_state[storage_address]['<STR_LIT>'][offset] = value<EOL>

Writes a value to a storage slot in specified account

:param storage_address: an account address
:param offset: the storage slot to use.
:type offset: int or BitVec
:param value: the value to write
:type value: int or BitVec


storage = self._world_state[address]['<STR_LIT>']<EOL>items = []<EOL>array = storage.array<EOL>while not isinstance(array, ArrayVariable):<EOL><INDENT>items.append((array.index, array.value))<EOL>array = array.array<EOL><DEDENT>return items<EOL>

Gets all items in an account storage

:param address: account address
:return: all items in account storage. items are tuple of (index, value). value can be symbolic
:rtype: list[(storage_index, storage_value)]


storage = self._world_state[address]['<STR_LIT>']<EOL>array = storage.array<EOL>while not isinstance(array, ArrayVariable):<EOL><INDENT>if isinstance(array, ArrayStore):<EOL><INDENT>return True<EOL><DEDENT>array = array.array<EOL><DEDENT>return False<EOL>

True if something has been written to the storage.
Note that if a slot has been erased from the storage this function may
lose any meaning.


return self._world_state[address]['<STR_LIT>']<EOL>

Gets the storage of an account

:param address: account address
:return: account storage
:rtype: bytearray or ArrayProxy


def _set_storage(self, address, storage):

self._world_state[address]['<STR_LIT>'] = storage<EOL>

Private auxiliary function to replace the storage


def block_hash(self, block_number=None, force_recent=True):

if block_number is None:<EOL><INDENT>block_number = self.block_number() - <NUM_LIT:1><EOL><DEDENT>value = sha3.keccak_256((repr(block_number) + '<STR_LIT>').encode()).hexdigest()<EOL>value = int(value, <NUM_LIT:16>)<EOL>if force_recent:<EOL><INDENT>bnmax = Operators.ITEBV(<NUM_LIT>, self.block_number() > <NUM_LIT>, <NUM_LIT>, self.block_number())<EOL>value = Operators.ITEBV(<NUM_LIT>, Operators.OR(block_number >= self.block_number(), block_number < bnmax), <NUM_LIT:0>, value)<EOL><DEDENT>return value<EOL>

Calculates a block's hash
:param block_number: the block number for which to calculate the hash, defaulting to the most recent block
:param force_recent: if True (the default) return zero for any block that is in the future or older than 256 blocks
:return: the block hash


def new_address(self, sender=None, nonce=None):

if sender is not None and nonce is None:<EOL><INDENT>nonce = self.get_nonce(sender)<EOL><DEDENT>new_address = self.calculate_new_address(sender, nonce)<EOL>if sender is None and new_address in self:<EOL><INDENT>return self.new_address(sender, nonce)<EOL><DEDENT>return new_address<EOL>


def create_account(self, address=None, balance=<NUM_LIT:0>, code=None, storage=None, nonce=None):

if code is None:<EOL><INDENT>code = bytes()<EOL><DEDENT>else:<EOL><INDENT>if not isinstance(code, (bytes, Array)):<EOL><INDENT>raise EthereumError('<STR_LIT>')<EOL><DEDENT><DEDENT>if nonce is None:<EOL><INDENT>nonce = <NUM_LIT:1> if code else <NUM_LIT:0><EOL><DEDENT>if address is None:<EOL><INDENT>address = self.new_address()<EOL><DEDENT>if not isinstance(address, int):<EOL><INDENT>raise EthereumError('<STR_LIT>')<EOL><DEDENT>if address in self.accounts:<EOL><INDENT>raise EthereumError('<STR_LIT>')<EOL><DEDENT>if storage is None:<EOL><INDENT>storage = self.constraints.new_array(index_bits=<NUM_LIT>, value_bits=<NUM_LIT>, name=f'<STR_LIT>', avoid_collisions=True, default=<NUM_LIT:0>)<EOL><DEDENT>else:<EOL><INDENT>if isinstance(storage, ArrayProxy):<EOL><INDENT>if storage.index_bits != <NUM_LIT> or storage.value_bits != <NUM_LIT>:<EOL><INDENT>raise TypeError("<STR_LIT>")<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if any((k < <NUM_LIT:0> or k >= <NUM_LIT:1> << <NUM_LIT> for k, v in storage.items())):<EOL><INDENT>raise TypeError("<STR_LIT>")<EOL><DEDENT><DEDENT><DEDENT>self._world_state[address] = {}<EOL>self._world_state[address]['<STR_LIT>'] = nonce<EOL>self._world_state[address]['<STR_LIT>'] = balance<EOL>self._world_state[address]['<STR_LIT>'] = storage<EOL>self._world_state[address]['<STR_LIT:code>'] = code<EOL>data = binascii.unhexlify('<STR_LIT>'.format(address, <NUM_LIT:0>))<EOL>value = sha3.keccak_256(data).hexdigest()<EOL>value = int(value, <NUM_LIT:16>)<EOL>self._publish('<STR_LIT>', data, value)<EOL>return address<EOL>

Low level account creation. No transaction is done.
:param address: the address of the account, if known. If omitted, a new address will be generated as closely to the Yellow Paper as possible.
:param balance: the initial balance of the account in Wei
:param code: the runtime code of the account, if a contract
:param storage: storage array
:param nonce: the nonce for the account; contracts should have a nonce greater than or equal to 1


def create_contract(self, price=<NUM_LIT:0>, address=None, caller=None, balance=<NUM_LIT:0>, init=None, gas=None):

expected_address = self.create_account(self.new_address(sender=caller))<EOL>if address is None:<EOL><INDENT>address = expected_address<EOL><DEDENT>elif caller is not None and address != expected_address:<EOL><INDENT>raise EthereumError(f"<STR_LIT>")<EOL><DEDENT>self.start_transaction('<STR_LIT>', address, price, init, caller, balance, gas=gas)<EOL>self._process_pending_transaction()<EOL>return address<EOL>

Create a contract account. Sends a transaction to initialize the contract

:param address: the address of the new account, if known. If omitted, a new address will be generated as closely to the Yellow Paper as possible.
:param balance: the initial balance of the account in Wei
:param init: the initialization code of the contract

The way that the Solidity compiler expects the constructor arguments to
be passed is by appending the arguments to the byte code produced by the
Solidity compiler. The arguments are formatted as defined in the Ethereum
ABI2. The arguments are then copied from the init byte array to the EVM
memory through the CODECOPY opcode with appropriate values on the stack.
This is done when the byte code in the init byte array is actually run
on the network.


def start_transaction(self, sort, address, price=None, data=None, caller=None, value=<NUM_LIT:0>, gas=<NUM_LIT>):

assert self._pending_transaction is None, "<STR_LIT>"<EOL>self._pending_transaction = PendingTransaction(sort, address, price, data, caller, value, gas)<EOL>

Initiate a transaction
:param sort: the type of transaction. CREATE or CALL or DELEGATECALL
:param address: the address of the account which owns the code that is executing.
:param price: the price of gas in the transaction that originated this execution.
:param data: the byte array that is the input data to this execution
:param caller: the address of the account which caused the code to be executing. A 160-bit code used for identifying Accounts
:param value: the value, in Wei, passed to this account as part of the same procedure as execution. One Ether is defined as being 10**18 Wei.
:param bytecode: the byte array that is the machine code to be executed.
:param gas: gas budget for this transaction.


programs = programs.split("<STR_LIT:U+002C>")<EOL>super().__init__(path=programs[<NUM_LIT:0>], **kwargs)<EOL>self.program = programs[<NUM_LIT:0>]<EOL>self.clocks = <NUM_LIT:0><EOL>self.files = []<EOL>self.syscall_trace = []<EOL>self.files = []<EOL>logger.info("<STR_LIT>")<EOL>self.input = Socket()<EOL>self.output = Socket()<EOL>stdin = Socket()<EOL>stdout = Socket()<EOL>stderr = Socket()<EOL>stdin.peer = self.output<EOL>stdout.peer = self.output<EOL>stderr.peer = self.output<EOL>self.input.peer = stdin<EOL>assert self._open(stdin) == <NUM_LIT:0><EOL>assert self._open(stdout) == <NUM_LIT:1><EOL>assert self._open(stderr) == <NUM_LIT:2><EOL>self.procs = []<EOL>for program in programs:<EOL><INDENT>self.procs += self.load(program)<EOL>socka, sockb = Socket.pair()<EOL>self._open(socka)<EOL>self._open(sockb)<EOL><DEDENT>nprocs = len(self.procs)<EOL>nfiles = len(self.files)<EOL>assert nprocs > <NUM_LIT:0><EOL>self.running = list(range(nprocs))<EOL>self._current = <NUM_LIT:0><EOL>self.timers = [None] * nprocs<EOL>self.rwait = [set() for _ in range(nfiles)]<EOL>self.twait = [set() for _ in range(nfiles)]<EOL>for proc in self.procs:<EOL><INDENT>self.forward_events_from(proc)<EOL><DEDENT>

Builds a Decree OS
:param cpus: CPU for this platform
:param mem: memory for this platform
:todo: generalize for more CPUs
:todo: fix deps?


super().__setstate__(state)<EOL>self.input = Socket()<EOL>self.input.buffer = state['<STR_LIT:input>']<EOL>self.output = Socket()<EOL>self.output.buffer = state['<STR_LIT>']<EOL>self.files = []<EOL>for buf in state['<STR_LIT>']:<EOL><INDENT>f = Socket()<EOL>f.buffer = buf<EOL>self.files.append(f)<EOL><DEDENT>for fd in range(len(self.files)):<EOL><INDENT>if self.connections(fd) is not None:<EOL><INDENT>self.files[fd].peer = self.files[self.connections(fd)]<EOL><DEDENT><DEDENT>self.files[<NUM_LIT:0>].peer = self.output<EOL>self.files[<NUM_LIT:1>].peer = self.output<EOL>self.files[<NUM_LIT:2>].peer = self.output<EOL>self.input.peer = self.files[<NUM_LIT:0>]<EOL>self.procs = state['<STR_LIT>']<EOL>self._current = state['<STR_LIT>']<EOL>self.running = state['<STR_LIT>']<EOL>self.rwait = state['<STR_LIT>']<EOL>self.twait = state['<STR_LIT>']<EOL>self.timers = state['<STR_LIT>']<EOL>self.clocks = state['<STR_LIT>']<EOL>self.syscall_trace = state['<STR_LIT>']<EOL>for proc in self.procs:<EOL><INDENT>self.forward_events_from(proc)<EOL><DEDENT>

:todo: some asserts
:todo: fix deps? (last line)


filename = "<STR_LIT>"<EOL>for i in range(<NUM_LIT:0>, <NUM_LIT>):<EOL><INDENT>c = Operators.CHR(cpu.read_int(buf + i, <NUM_LIT:8>))<EOL>if c == '<STR_LIT:\x00>':<EOL><INDENT>break<EOL><DEDENT>filename += c<EOL><DEDENT>return filename<EOL>

Reads a null terminated concrete buffer form memory
:todo: FIX. move to cpu or memory


CGC_MIN_PAGE_SIZE = <NUM_LIT><EOL>CGC_MIN_ALIGN = CGC_MIN_PAGE_SIZE<EOL>TASK_SIZE = <NUM_LIT><EOL>def CGC_PAGESTART(_v):<EOL><INDENT>return ((_v) & ~ (CGC_MIN_ALIGN - <NUM_LIT:1>))<EOL><DEDENT>def CGC_PAGEOFFSET(_v):<EOL><INDENT>return ((_v) & (CGC_MIN_ALIGN - <NUM_LIT:1>))<EOL><DEDENT>def CGC_PAGEALIGN(_v):<EOL><INDENT>return (((_v) + CGC_MIN_ALIGN - <NUM_LIT:1>) & ~(CGC_MIN_ALIGN - <NUM_LIT:1>))<EOL><DEDENT>def BAD_ADDR(x):<EOL><INDENT>return ((x) >= TASK_SIZE)<EOL><DEDENT>cgc = CGCElf(filename)<EOL>logger.info("<STR_LIT>" % (filename, cgc.arch))<EOL>cpu = self._mk_proc()<EOL>bss = brk = <NUM_LIT:0><EOL>start_code = <NUM_LIT><EOL>end_code = start_data = end_data = <NUM_LIT:0><EOL>for (vaddr, memsz, perms, name, offset, filesz) in cgc.maps():<EOL><INDENT>if vaddr < start_code:<EOL><INDENT>start_code = vaddr<EOL><DEDENT>if start_data < vaddr:<EOL><INDENT>start_data = vaddr<EOL><DEDENT>if vaddr > TASK_SIZE or filesz > memsz ormemsz > TASK_SIZE or TASK_SIZE - memsz < vaddr:<EOL><INDENT>raise Exception("<STR_LIT>")<EOL><DEDENT>addr = None<EOL>if filesz > <NUM_LIT:0>:<EOL><INDENT>hint = CGC_PAGESTART(vaddr)<EOL>size = CGC_PAGEALIGN(filesz + CGC_PAGEOFFSET(vaddr))<EOL>offset = CGC_PAGESTART(offset)<EOL>addr = cpu.memory.mmapFile(hint, size, perms, name, offset)<EOL>assert not BAD_ADDR(addr)<EOL>lo = CGC_PAGEALIGN(vaddr + filesz)<EOL>hi = CGC_PAGEALIGN(vaddr + memsz)<EOL><DEDENT>else:<EOL><INDENT>lo = CGC_PAGESTART(vaddr + filesz)<EOL>hi = CGC_PAGEALIGN(vaddr + memsz)<EOL><DEDENT>if hi - lo > <NUM_LIT:0>:<EOL><INDENT>zaddr = cpu.memory.mmap(lo, hi - lo, perms)<EOL>assert not BAD_ADDR(zaddr)<EOL><DEDENT>lo = vaddr + filesz<EOL>hi = CGC_PAGEALIGN(vaddr + memsz)<EOL>if hi - lo > <NUM_LIT:0>:<EOL><INDENT>old_perms = cpu.memory.perms(lo)<EOL>cpu.memory.mprotect(lo, hi - lo, '<STR_LIT>')<EOL>try:<EOL><INDENT>cpu.memory[lo:hi] = '<STR_LIT:\x00>' * (hi - lo)<EOL><DEDENT>except Exception as e:<EOL><INDENT>logger.debug("<STR_LIT>" % str(e))<EOL><DEDENT>cpu.memory.mprotect(lo, hi, old_perms)<EOL><DEDENT>if addr is None:<EOL><INDENT>addr = zaddr<EOL><DEDENT>assert addr is not None<EOL>k = vaddr + filesz<EOL>if k > bss:<EOL><INDENT>bss = k<EOL><DEDENT>if '<STR_LIT:x>' in perms and end_code < k:<EOL><INDENT>end_code = k<EOL><DEDENT>if end_data < k:<EOL><INDENT>end_data = k<EOL><DEDENT>k = vaddr + memsz<EOL>if k > brk:<EOL><INDENT>brk = k<EOL><DEDENT><DEDENT>bss = brk<EOL>stack_base = <NUM_LIT><EOL>stack_size = <NUM_LIT><EOL>stack = cpu.memory.mmap(<NUM_LIT> - stack_size, stack_size, '<STR_LIT>') + stack_size - <NUM_LIT:4><EOL>assert (stack_base) in cpu.memory and (stack_base - stack_size + <NUM_LIT:4>) in cpu.memory<EOL>status, thread = next(cgc.threads())<EOL>assert status == '<STR_LIT>'<EOL>logger.info("<STR_LIT>")<EOL>cpu.write_register('<STR_LIT>', <NUM_LIT>)<EOL>cpu.write_register('<STR_LIT>', cpu.memory.mmap(CGC_PAGESTART(<NUM_LIT>),<EOL>CGC_PAGEALIGN(<NUM_LIT> + CGC_PAGEOFFSET(<NUM_LIT>)),<EOL>'<STR_LIT>'))<EOL>cpu.write_register('<STR_LIT>', <NUM_LIT>)<EOL>cpu.write_register('<STR_LIT>', <NUM_LIT>)<EOL>cpu.write_register('<STR_LIT>', stack)<EOL>cpu.write_register('<STR_LIT>', <NUM_LIT>)<EOL>cpu.write_register('<STR_LIT>', <NUM_LIT>)<EOL>cpu.write_register('<STR_LIT>', <NUM_LIT>)<EOL>cpu.write_register('<STR_LIT>', thread['<STR_LIT>'])<EOL>cpu.write_register('<STR_LIT>', <NUM_LIT>)<EOL>cpu.write_register('<STR_LIT>', <NUM_LIT>)<EOL>cpu.write_register('<STR_LIT>', <NUM_LIT>)<EOL>cpu.write_register('<STR_LIT>', <NUM_LIT>)<EOL>cpu.write_register('<STR_LIT>', <NUM_LIT>)<EOL>cpu.write_register('<STR_LIT>', <NUM_LIT>)<EOL>cpu.write_register('<STR_LIT>', <NUM_LIT>)<EOL>cpu.memory.mmap(<NUM_LIT>, <NUM_LIT>, '<STR_LIT:r>')<EOL>logger.info("<STR_LIT>", cpu.EIP)<EOL>logger.info("<STR_LIT>", cpu.ESP)<EOL>logger.info("<STR_LIT>", brk)<EOL>logger.info("<STR_LIT>")<EOL>for m in str(cpu.memory).split('<STR_LIT:\n>'):<EOL><INDENT>logger.info("<STR_LIT>", m)<EOL><DEDENT>return [cpu]<EOL>

Loads a CGC-ELF program in memory and prepares the initial CPU state
and the stack.

:param filename: pathname of the file to be executed.


self.files[fd] = None<EOL>

Closes a file descriptor
:rtype: int
:param fd: the file descriptor to close.
:return: C{0} on success.


return self._open(self.files[fd])<EOL>

Duplicates a file descriptor
:rtype: int
:param fd: the file descriptor to close.
:return: C{0} on success.


def sys_allocate(self, cpu, length, isX, addr):

<EOL>if addr not in cpu.memory:<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return Decree.CGC_EFAULT<EOL><DEDENT>perms = ['<STR_LIT>', '<STR_LIT>'][bool(isX)]<EOL>try:<EOL><INDENT>result = cpu.memory.mmap(None, length, perms)<EOL><DEDENT>except Exception as e:<EOL><INDENT>logger.info("<STR_LIT>", str(e), length)<EOL>return Decree.CGC_ENOMEM<EOL><DEDENT>cpu.write_int(addr, result, <NUM_LIT:32>)<EOL>logger.info("<STR_LIT>" % (length, perms, addr, result))<EOL>self.syscall_trace.append(("<STR_LIT>", -<NUM_LIT:1>, length))<EOL>return <NUM_LIT:0><EOL>

allocate - allocate virtual memory

           The  allocate  system call creates a new allocation in the virtual address
           space of the calling process.  The length argument specifies the length of
           the allocation in bytes which will be rounded up to the hardware page size.

           The kernel chooses the address at which to create the allocation; the
           address of the new allocation is returned in *addr as the result of the call.

           All newly allocated memory is readable and writeable. In addition, the
           is_X argument is a boolean that allows newly allocated memory to be marked
           as executable (non-zero) or non-executable (zero).

           The allocate function is invoked through system call number 5.

           :param cpu: current CPU
           :param length: the length of the allocation in bytes
           :param isX: boolean that allows newly allocated memory to be marked as executable
           :param addr: the address of the new allocation is returned in *addr

           :return: On success, allocate returns zero and a pointer to the allocated area
                               is returned in *addr.  Otherwise, an error code is returned
                               and *addr is undefined.
                   EINVAL   length is zero.
                   EINVAL   length is too large.
                   EFAULT   addr points to an invalid address.
                   ENOMEM   No memory is available or the process' maximum number of allocations
                            would have been exceeded.


def sys_random(self, cpu, buf, count, rnd_bytes):

ret = <NUM_LIT:0><EOL>if count != <NUM_LIT:0>:<EOL><INDENT>if count > Decree.CGC_SSIZE_MAX or count < <NUM_LIT:0>:<EOL><INDENT>ret = Decree.CGC_EINVAL<EOL><DEDENT>else:<EOL><INDENT>if buf not in cpu.memory or (buf + count) not in cpu.memory:<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return Decree.CGC_EFAULT<EOL><DEDENT>with open("<STR_LIT>", "<STR_LIT:rb>") as f:<EOL><INDENT>data = f.read(count)<EOL><DEDENT>self.syscall_trace.append(("<STR_LIT>", -<NUM_LIT:1>, data))<EOL>cpu.write_bytes(buf, data)<EOL><DEDENT><DEDENT>if rnd_bytes:<EOL><INDENT>if rnd_bytes not in cpu.memory:<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return Decree.CGC_EFAULT<EOL><DEDENT>cpu.write_int(rnd_bytes, len(data), <NUM_LIT:32>)<EOL><DEDENT>logger.info("<STR_LIT>" % (buf, count, rnd_bytes, repr(data[:<NUM_LIT:10>])))<EOL>return ret<EOL>

random - fill a buffer with random data

           The  random  system call populates the buffer referenced by buf with up to
           count bytes of random data. If count is zero, random returns 0 and optionally
           sets *rx_bytes to zero. If count is greater than SSIZE_MAX, the result is unspecified.

           :param cpu: current CPU
           :param buf: a memory buffer
           :param count: max number of bytes to receive
           :param rnd_bytes: if valid, points to the actual number of random bytes

           :return:  0        On success
                     EINVAL   count is invalid.
                     EFAULT   buf or rnd_bytes points to an invalid address.


def sys_receive(self, cpu, fd, buf, count, rx_bytes):

data = '<STR_LIT>'<EOL>if count != <NUM_LIT:0>:<EOL><INDENT>if not self._is_open(fd):<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return Decree.CGC_EBADF<EOL><DEDENT>if buf not in cpu.memory:  <EOL><INDENT>logger.info("<STR_LIT>")<EOL>return Decree.CGC_EFAULT<EOL><DEDENT>if fd > <NUM_LIT:2> and self.files[fd].is_empty():<EOL><INDENT>cpu.PC -= cpu.instruction.size<EOL>self.wait([fd], [], None)<EOL>raise RestartSyscall()<EOL><DEDENT>data = self.files[fd].receive(count)<EOL>self.syscall_trace.append(("<STR_LIT>", fd, data))<EOL>cpu.write_bytes(buf, data)<EOL>self.signal_receive(fd)<EOL><DEDENT>if rx_bytes:<EOL><INDENT>if rx_bytes not in cpu.memory:<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return Decree.CGC_EFAULT<EOL><DEDENT>cpu.write_int(rx_bytes, len(data), <NUM_LIT:32>)<EOL><DEDENT>logger.info("<STR_LIT>" % (fd, buf, count, rx_bytes, repr(data)[:min(count, <NUM_LIT:10>)], len(data)))<EOL>return <NUM_LIT:0><EOL>

receive - receive bytes from a file descriptor

            The receive system call reads up to count bytes from file descriptor fd to the
            buffer pointed to by buf. If count is zero, receive returns 0 and optionally
            sets *rx_bytes to zero.

            :param cpu: current CPU.
            :param fd: a valid file descriptor
            :param buf: a memory buffer
            :param count: max number of bytes to receive
            :param rx_bytes: if valid, points to the actual number of bytes received
            :return: 0            Success
                     EBADF        fd is not a valid file descriptor or is not open
                     EFAULT       buf or rx_bytes points to an invalid address.


def sys_transmit(self, cpu, fd, buf, count, tx_bytes):

data = []<EOL>if count != <NUM_LIT:0>:<EOL><INDENT>if not self._is_open(fd):<EOL><INDENT>logger.error("<STR_LIT>", fd)<EOL>return Decree.CGC_EBADF<EOL><DEDENT>if buf not in cpu.memory or (buf + count) not in cpu.memory:<EOL><INDENT>logger.debug("<STR_LIT>")<EOL>return Decree.CGC_EFAULT<EOL><DEDENT>if fd > <NUM_LIT:2> and self.files[fd].is_full():<EOL><INDENT>cpu.PC -= cpu.instruction.size<EOL>self.wait([], [fd], None)<EOL>raise RestartSyscall()<EOL><DEDENT>for i in range(<NUM_LIT:0>, count):<EOL><INDENT>value = Operators.CHR(cpu.read_int(buf + i, <NUM_LIT:8>))<EOL>if not isinstance(value, str):<EOL><INDENT>logger.debug("<STR_LIT>", fd)<EOL><DEDENT>data.append(value)<EOL><DEDENT>self.files[fd].transmit(data)<EOL>logger.info("<STR_LIT>" % (fd, buf, count, tx_bytes, '<STR_LIT>'.join([str(x) for x in data])))<EOL>self.syscall_trace.append(("<STR_LIT>", fd, data))<EOL>self.signal_transmit(fd)<EOL><DEDENT>if tx_bytes:<EOL><INDENT>if tx_bytes not in cpu.memory:<EOL><INDENT>logger.debug("<STR_LIT>")<EOL>return Decree.CGC_EFAULT<EOL><DEDENT>cpu.write_int(tx_bytes, len(data), <NUM_LIT:32>)<EOL><DEDENT>return <NUM_LIT:0><EOL>

transmit - send bytes through a file descriptor
          The  transmit system call writes up to count bytes from the buffer pointed
          to by buf to the file descriptor fd. If count is zero, transmit returns 0
          and optionally sets *tx_bytes to zero.

          :param cpu           current CPU
          :param fd            a valid file descriptor
          :param buf           a memory buffer
          :param count         number of bytes to send
          :param tx_bytes      if valid, points to the actual number of bytes transmitted
          :return: 0            Success
                   EBADF        fd is not a valid file descriptor or is not open.
                   EFAULT       buf or tx_bytes points to an invalid address.


def sys_terminate(self, cpu, error_code):

procid = self.procs.index(cpu)<EOL>self.sched()<EOL>self.running.remove(procid)<EOL>if issymbolic(error_code):<EOL><INDENT>logger.info("<STR_LIT>", procid, solver.minmax(self.constraints, error_code))<EOL><DEDENT>else:<EOL><INDENT>logger.info("<STR_LIT>", procid, error_code)<EOL><DEDENT>if len(self.running) == <NUM_LIT:0>:<EOL><INDENT>raise TerminateState(f'<STR_LIT>')<EOL><DEDENT>return error_code<EOL>

Exits all threads in a process
:param cpu: current CPU.
:raises Exception: 'Finished'


def sys_deallocate(self, cpu, addr, size):

logger.info("<STR_LIT>" % (addr, size))<EOL>if addr & <NUM_LIT> != <NUM_LIT:0>:<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return Decree.CGC_EINVAL<EOL><DEDENT>if size == <NUM_LIT:0>:<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return Decree.CGC_EINVAL<EOL><DEDENT>cpu.memory.munmap(addr, size)<EOL>self.syscall_trace.append(("<STR_LIT>", -<NUM_LIT:1>, size))<EOL>return <NUM_LIT:0><EOL>

deallocate - remove allocations
        The  deallocate  system call deletes the allocations for the specified
        address range, and causes further references to the addresses within the
        range to generate invalid memory accesses. The region is also
        automatically deallocated when the process is terminated.

        The address addr must be a multiple of the page size.  The length parameter
        specifies the size of the region to be deallocated in bytes.  All pages
        containing a part of the indicated range are deallocated, and subsequent
        references will terminate the process.  It is not an error if the indicated
        range does not contain any allocated pages.

        The deallocate function is invoked through system call number 6.

        :param cpu: current CPU
        :param addr: the starting address to unmap.
        :param size: the size of the portion to unmap.
        :return 0        On success
                EINVAL   addr is not page aligned.
                EINVAL   length is zero.
                EINVAL   any  part  of  the  region  being  deallocated  is outside the valid
                         address range of the process.

        :param cpu: current CPU.
        :return: C{0} on success.


def sys_fdwait(self, cpu, nfds, readfds, writefds, timeout, readyfds):

logger.debug("<STR_LIT>" % (nfds, readfds, writefds, timeout, readyfds))<EOL>if timeout:<EOL><INDENT>if timeout not in cpu.memory:  <EOL><INDENT>logger.info("<STR_LIT>")<EOL>return Decree.CGC_EFAULT<EOL><DEDENT><DEDENT>if readyfds:<EOL><INDENT>if readyfds not in cpu.memory:<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return Decree.CGC_EFAULT<EOL><DEDENT><DEDENT>writefds_wait = set()<EOL>writefds_ready = set()<EOL>fds_bitsize = (nfds + <NUM_LIT:7>) & ~<NUM_LIT:7><EOL>if writefds:<EOL><INDENT>if writefds not in cpu.memory:<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return Decree.CGC_EFAULT<EOL><DEDENT>bits = cpu.read_int(writefds, fds_bitsize)<EOL>for fd in range(nfds):<EOL><INDENT>if (bits & <NUM_LIT:1> << fd):<EOL><INDENT>if self.files[fd].is_full():<EOL><INDENT>writefds_wait.add(fd)<EOL><DEDENT>else:<EOL><INDENT>writefds_ready.add(fd)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>readfds_wait = set()<EOL>readfds_ready = set()<EOL>if readfds:<EOL><INDENT>if readfds not in cpu.memory:<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return Decree.CGC_EFAULT<EOL><DEDENT>bits = cpu.read_int(readfds, fds_bitsize)<EOL>for fd in range(nfds):<EOL><INDENT>if (bits & <NUM_LIT:1> << fd):<EOL><INDENT>if self.files[fd].is_empty():<EOL><INDENT>readfds_wait.add(fd)<EOL><DEDENT>else:<EOL><INDENT>readfds_ready.add(fd)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>n = len(readfds_ready) + len(writefds_ready)<EOL>if n == <NUM_LIT:0>:<EOL><INDENT>if timeout != <NUM_LIT:0>:<EOL><INDENT>seconds = cpu.read_int(timeout, <NUM_LIT:32>)<EOL>microseconds = cpu.read_int(timeout + <NUM_LIT:4>, <NUM_LIT:32>)<EOL>logger.info("<STR_LIT>", repr(<EOL>list(readfds_wait)), repr(list(writefds_wait)), microseconds + <NUM_LIT:1000> * seconds)<EOL>to = microseconds + <NUM_LIT:1000> * seconds<EOL><DEDENT>else:<EOL><INDENT>to = None<EOL>logger.info("<STR_LIT>",<EOL>repr(list(readfds_wait)), repr(list(writefds_wait)))<EOL><DEDENT>cpu.PC -= cpu.instruction.size<EOL>self.wait(readfds_wait, writefds_wait, to)<EOL>raise RestartSyscall()  <EOL><DEDENT>if readfds:<EOL><INDENT>bits = <NUM_LIT:0><EOL>for fd in readfds_ready:<EOL><INDENT>bits |= <NUM_LIT:1> << fd<EOL><DEDENT>for byte in range(<NUM_LIT:0>, nfds, <NUM_LIT:8>):<EOL><INDENT>cpu.write_int(readfds, (bits >> byte) & <NUM_LIT>, <NUM_LIT:8>)<EOL><DEDENT><DEDENT>if writefds:<EOL><INDENT>bits = <NUM_LIT:0><EOL>for fd in writefds_ready:<EOL><INDENT>bits |= <NUM_LIT:1> << fd<EOL><DEDENT>for byte in range(<NUM_LIT:0>, nfds, <NUM_LIT:8>):<EOL><INDENT>cpu.write_int(writefds, (bits >> byte) & <NUM_LIT>, <NUM_LIT:8>)<EOL><DEDENT><DEDENT>logger.info("<STR_LIT>", readyfds)<EOL>if readyfds:<EOL><INDENT>cpu.write_int(readyfds, n, <NUM_LIT:32>)<EOL><DEDENT>self.syscall_trace.append(("<STR_LIT>", -<NUM_LIT:1>, None))<EOL>return <NUM_LIT:0><EOL>

fdwait - wait for file descriptors to become ready


syscalls = {<NUM_LIT>: self.sys_terminate,<EOL><NUM_LIT>: self.sys_transmit,<EOL><NUM_LIT>: self.sys_receive,<EOL><NUM_LIT>: self.sys_fdwait,<EOL><NUM_LIT>: self.sys_allocate,<EOL><NUM_LIT>: self.sys_deallocate,<EOL><NUM_LIT>: self.sys_random,<EOL>}<EOL>if cpu.EAX not in syscalls.keys():<EOL><INDENT>raise TerminateState(f"<STR_LIT>")<EOL><DEDENT>func = syscalls[cpu.EAX]<EOL>logger.debug("<STR_LIT>", func.__name__, func.__code__.co_argcount)<EOL>nargs = func.__code__.co_argcount<EOL>args = [cpu, cpu.EBX, cpu.ECX, cpu.EDX, cpu.ESI, cpu.EDI, cpu.EBP]<EOL>cpu.EAX = func(*args[:nargs - <NUM_LIT:1>])<EOL>

32 bit dispatcher.
:param cpu: current CPU.
_terminate, transmit, receive, fdwait, allocate, deallocate and random


if len(self.procs) > <NUM_LIT:1>:<EOL><INDENT>logger.info("<STR_LIT>")<EOL>logger.info("<STR_LIT>", self.procs)<EOL>logger.info("<STR_LIT>", self.running)<EOL>logger.info("<STR_LIT>", self.rwait)<EOL>logger.info("<STR_LIT>", self.twait)<EOL>logger.info("<STR_LIT>", self.timers)<EOL>logger.info("<STR_LIT>", self.clocks)<EOL>logger.info("<STR_LIT>", self._current)<EOL><DEDENT>if len(self.running) == <NUM_LIT:0>:<EOL><INDENT>logger.info("<STR_LIT>")<EOL>if all([x is None for x in self.timers]):<EOL><INDENT>raise Deadlock()<EOL><DEDENT>self.clocks = min([x for x in self.timers if x is not None]) + <NUM_LIT:1><EOL>self.check_timers()<EOL>assert len(self.running) != <NUM_LIT:0>, "<STR_LIT>"<EOL>self._current = self.running[<NUM_LIT:0>]<EOL>return<EOL><DEDENT>next_index = (self.running.index(self._current) + <NUM_LIT:1>) % len(self.running)<EOL>next = self.running[next_index]<EOL>if len(self.procs) > <NUM_LIT:1>:<EOL><INDENT>logger.info("<STR_LIT>", self._current, next)<EOL><DEDENT>self._current = next<EOL>

Yield CPU.
            This will choose another process from the RUNNNIG list and change
            current running process. May give the same cpu if only one running
            process.


def wait(self, readfds, writefds, timeout):

logger.info("<STR_LIT>")<EOL>logger.info("<STR_LIT>", self._current, readfds, writefds, timeout)<EOL>logger.info("<STR_LIT>", self.procs)<EOL>logger.info("<STR_LIT>", self.running)<EOL>logger.info("<STR_LIT>", self.rwait)<EOL>logger.info("<STR_LIT>", self.twait)<EOL>logger.info("<STR_LIT>", self.timers)<EOL>for fd in readfds:<EOL><INDENT>self.rwait[fd].add(self._current)<EOL><DEDENT>for fd in writefds:<EOL><INDENT>self.twait[fd].add(self._current)<EOL><DEDENT>if timeout is not None:<EOL><INDENT>self.timers[self._current] = self.clocks + timeout<EOL><DEDENT>else:<EOL><INDENT>self.timers[self._current] = None<EOL><DEDENT>procid = self._current<EOL>next_index = (self.running.index(procid) + <NUM_LIT:1>) % len(self.running)<EOL>self._current = self.running[next_index]<EOL>logger.info("<STR_LIT>", procid, self._current)<EOL>logger.info("<STR_LIT>", procid, self.running, self._current)<EOL>self.running.remove(procid)<EOL>if self._current not in self.running:<EOL><INDENT>logger.info("<STR_LIT>")<EOL>self._current = None<EOL>if all([x is None for x in self.timers]):<EOL><INDENT>raise Deadlock()<EOL><DEDENT>self.check_timers()<EOL><DEDENT>

Wait for filedescriptors or timeout.
            Adds the current process to the corresponding waiting list and
            yields the cpu to another running process.


logger.info("<STR_LIT>", procid)<EOL>for wait_list in self.rwait:<EOL><INDENT>if procid in wait_list:<EOL><INDENT>wait_list.remove(procid)<EOL><DEDENT><DEDENT>for wait_list in self.twait:<EOL><INDENT>if procid in wait_list:<EOL><INDENT>wait_list.remove(procid)<EOL><DEDENT><DEDENT>self.timers[procid] = None<EOL>self.running.append(procid)<EOL>if self._current is None:<EOL><INDENT>self._current = procid<EOL><DEDENT>

Remove procid from waitlists and reestablish it in the running list


connections = self.connections<EOL>if connections(fd) and self.twait[connections(fd)]:<EOL><INDENT>procid = random.sample(self.twait[connections(fd)], <NUM_LIT:1>)[<NUM_LIT:0>]<EOL>self.awake(procid)<EOL><DEDENT>

Awake one process waiting to receive data on fd


connections = self.connections<EOL>if connections(fd) and self.rwait[connections(fd)]:<EOL><INDENT>procid = random.sample(self.rwait[connections(fd)], <NUM_LIT:1>)[<NUM_LIT:0>]<EOL>self.awake(procid)<EOL><DEDENT>

Awake one process waiting to transmit data on fd


if self._current is None:<EOL><INDENT>advance = min([x for x in self.timers if x is not None]) + <NUM_LIT:1><EOL>logger.info("<STR_LIT>", self.clocks, advance)<EOL>self.clocks = advance<EOL><DEDENT>for procid in range(len(self.timers)):<EOL><INDENT>if self.timers[procid] is not None:<EOL><INDENT>if self.clocks > self.timers[procid]:<EOL><INDENT>self.procs[procid].PC += self.procs[procid].instruction.size<EOL>self.awake(procid)<EOL><DEDENT><DEDENT><DEDENT>


try:<EOL><INDENT>self.current.execute()<EOL>self.clocks += <NUM_LIT:1><EOL>if self.clocks % <NUM_LIT> == <NUM_LIT:0>:<EOL><INDENT>self.check_timers()<EOL>self.sched()<EOL><DEDENT><DEDENT>except Interruption as e:<EOL><INDENT>if e.N != <NUM_LIT>:<EOL><INDENT>raise<EOL><DEDENT>try:<EOL><INDENT>self.int80(self.current)<EOL><DEDENT>except RestartSyscall:<EOL><INDENT>pass<EOL><DEDENT><DEDENT>return True<EOL>

Execute one cpu instruction in the current thread (only one supported).
:rtype: bool
:return: C{True}

:todo: This is where we could implement a simple schedule.


def __init__(self, constraints, programs, symbolic_random=None):

self.random = <NUM_LIT:0><EOL>self._constraints = constraints<EOL>super().__init__(programs)<EOL>

Builds a symbolic extension of a Decree OS
:param constraints: a constraint set
:param cpus: CPU for this platform
:param mem: memory for this platform


if issymbolic(fd):<EOL><INDENT>logger.info("<STR_LIT>")<EOL>cpu.PC = cpu.PC - cpu.instruction.size<EOL>raise SymbolicSyscallArgument(cpu, <NUM_LIT:0>)<EOL><DEDENT>if issymbolic(buf):<EOL><INDENT>logger.info("<STR_LIT>")<EOL>cpu.PC = cpu.PC - cpu.instruction.size<EOL>raise SymbolicSyscallArgument(cpu, <NUM_LIT:1>)<EOL><DEDENT>if issymbolic(count):<EOL><INDENT>logger.info("<STR_LIT>")<EOL>cpu.PC = cpu.PC - cpu.instruction.size<EOL>raise SymbolicSyscallArgument(cpu, <NUM_LIT:2>)<EOL><DEDENT>if issymbolic(rx_bytes):<EOL><INDENT>logger.info("<STR_LIT>")<EOL>cpu.PC = cpu.PC - cpu.instruction.size<EOL>raise SymbolicSyscallArgument(cpu, <NUM_LIT:3>)<EOL><DEDENT>return super().sys_receive(cpu, fd, buf, count, rx_bytes)<EOL>


if issymbolic(fd):<EOL><INDENT>logger.info("<STR_LIT>")<EOL>cpu.PC = cpu.PC - cpu.instruction.size<EOL>raise SymbolicSyscallArgument(cpu, <NUM_LIT:0>)<EOL><DEDENT>if issymbolic(buf):<EOL><INDENT>logger.info("<STR_LIT>")<EOL>cpu.PC = cpu.PC - cpu.instruction.size<EOL>raise SymbolicSyscallArgument(cpu, <NUM_LIT:1>)<EOL><DEDENT>if issymbolic(count):<EOL><INDENT>logger.info("<STR_LIT>")<EOL>cpu.PC = cpu.PC - cpu.instruction.size<EOL>raise SymbolicSyscallArgument(cpu, <NUM_LIT:2>)<EOL><DEDENT>if issymbolic(tx_bytes):<EOL><INDENT>logger.info("<STR_LIT>")<EOL>cpu.PC = cpu.PC - cpu.instruction.size<EOL>raise SymbolicSyscallArgument(cpu, <NUM_LIT:3>)<EOL><DEDENT>return super().sys_transmit(cpu, fd, buf, count, tx_bytes)<EOL>


return<EOL>

Flush buffered data. Currently not implemented.


def __init__(self, constraints, path="<STR_LIT>", mode='<STR_LIT>', max_size=<NUM_LIT:100>,<EOL>wildcard='<STR_LIT:+>'):

super().__init__(path, mode)<EOL>data = self.file.read()<EOL>self._constraints = constraints<EOL>self.pos = <NUM_LIT:0><EOL>self.max_size = min(len(data), max_size)<EOL>size = len(data)<EOL>self.array = constraints.new_array(name=self.name, index_max=size)<EOL>symbols_cnt = <NUM_LIT:0><EOL>for i in range(size):<EOL><INDENT>if data[i] != wildcard:<EOL><INDENT>self.array[i] = data[i]<EOL><DEDENT>else:<EOL><INDENT>symbols_cnt += <NUM_LIT:1><EOL><DEDENT><DEDENT>if symbols_cnt > max_size:<EOL><INDENT>logger.warning(("<STR_LIT>",<EOL>"<STR_LIT>"),<EOL>symbols_cnt,<EOL>max_size)<EOL><DEDENT>else:<EOL><INDENT>logger.debug("<STR_LIT>",<EOL>symbols_cnt,<EOL>self.name)<EOL><DEDENT>

Builds a symbolic file

:param constraints: the SMT constraints
:param str path: the pathname of the symbolic file
:param str mode: the access permissions of the symbolic file
:param max_size: Maximum amount of bytes of the symbolic file
:param str wildcard: Wildcard to be used in symbolic file


return self.pos<EOL>

Returns the read/write file offset
:rtype: int
:return: the read/write file offset.


def seek(self, offset, whence=os.SEEK_SET):

assert isinstance(offset, int)<EOL>assert whence in (os.SEEK_SET, os.SEEK_CUR, os.SEEK_END)<EOL>new_position = <NUM_LIT:0><EOL>if whence == os.SEEK_SET:<EOL><INDENT>new_position = offset<EOL><DEDENT>elif whence == os.SEEK_CUR:<EOL><INDENT>new_position = self.pos + offset<EOL><DEDENT>elif whence == os.SEEK_END:<EOL><INDENT>new_position = self.max_size + offset<EOL><DEDENT>if new_position < <NUM_LIT:0>:<EOL><INDENT>return -<NUM_LIT:1><EOL><DEDENT>self.pos = new_position<EOL>return self.pos<EOL>

Repositions the file C{offset} according to C{whence}.
Returns the resulting offset or -1 in case of error.
:rtype: int
:return: the file offset.


if self.pos > self.max_size:<EOL><INDENT>return []<EOL><DEDENT>else:<EOL><INDENT>size = min(count, self.max_size - self.pos)<EOL>ret = [self.array[i] for i in range(self.pos, self.pos + size)]<EOL>self.pos += size<EOL>return ret<EOL><DEDENT>

Reads up to C{count} bytes from the file.
:rtype: list
:return: the list of symbolic bytes read


size = min(len(data), self.max_size - self.pos)<EOL>for i in range(self.pos, self.pos + size):<EOL><INDENT>self.array[i] = data[i - self.pos]<EOL><DEDENT>

Writes the symbolic bytes in C{data} onto the file.


def __init__(self, program, argv=None, envp=None, disasm='<STR_LIT>', **kwargs):

super().__init__(path=program, **kwargs)<EOL>self.program = program<EOL>self.clocks = <NUM_LIT:0><EOL>self.files = []<EOL>self._closed_files = []<EOL>self.syscall_trace = []<EOL>self.programs = program<EOL>self.disasm = disasm<EOL>self.envp = envp<EOL>self.argv = argv<EOL>self._rlimits = {<EOL>resource.RLIMIT_NOFILE: (<NUM_LIT>, <NUM_LIT>),<EOL>resource.RLIMIT_STACK: (<NUM_LIT> * <NUM_LIT>, <NUM_LIT:0>)<EOL>}<EOL>if program is not None:<EOL><INDENT>self.elf = ELFFile(open(program, '<STR_LIT:rb>'))<EOL>self.arch = {'<STR_LIT>': '<STR_LIT>', '<STR_LIT>': '<STR_LIT>', '<STR_LIT>': '<STR_LIT>'}[self.elf.get_machine_arch()]<EOL>self._init_cpu(self.arch)<EOL>self._init_std_fds()<EOL>self._execve(program, argv, envp)<EOL><DEDENT>

Builds a Linux OS platform
:param string program: The path to ELF binary
:param string disasm: Disassembler to be used
:param list argv: The argv array; not including binary.
:param list envp: The ENV variables.
:ivar files: List of active file descriptors
:type files: list[Socket] or list[File]


platform = cls(None)<EOL>platform._init_cpu(arch)<EOL>platform._init_std_fds()<EOL>return platform<EOL>

Create a platform without an ELF loaded.

:param str arch: The architecture of the new platform
:rtype: Linux


argv = [] if argv is None else argv<EOL>envp = [] if envp is None else envp<EOL>logger.debug(f"<STR_LIT>")<EOL>self.load(program, envp)<EOL>self._arch_specific_init()<EOL>self._stack_top = self.current.STACK<EOL>self.setup_stack([program] + argv, envp)<EOL>nprocs = len(self.procs)<EOL>nfiles = len(self.files)<EOL>assert nprocs > <NUM_LIT:0><EOL>self.running = list(range(nprocs))<EOL>self.timers = [None] * nprocs<EOL>self.rwait = [set() for _ in range(nfiles)]<EOL>self.twait = [set() for _ in range(nfiles)]<EOL>for proc in self.procs:<EOL><INDENT>self.forward_events_from(proc)<EOL><DEDENT>

Load `program` and establish program state, such as stack and arguments.

:param program str: The ELF binary to load
:param argv list: argv array
:param envp list: envp array


super().__setstate__(state)<EOL>self.input = Socket()<EOL>self.input.buffer = state['<STR_LIT:input>']<EOL>self.output = Socket()<EOL>self.output.buffer = state['<STR_LIT>']<EOL>self.files = []<EOL>for ty, file_or_buffer in state['<STR_LIT>']:<EOL><INDENT>if ty == '<STR_LIT>':<EOL><INDENT>f = Socket()<EOL>f.buffer = file_or_buffer<EOL>self.files.append(f)<EOL><DEDENT>else:<EOL><INDENT>self.files.append(file_or_buffer)<EOL><DEDENT><DEDENT>self.files[<NUM_LIT:0>].peer = self.output<EOL>self.files[<NUM_LIT:1>].peer = self.output<EOL>self.files[<NUM_LIT:2>].peer = self.output<EOL>self._closed_files = state['<STR_LIT>']<EOL>self.input.peer = self.files[<NUM_LIT:0>]<EOL>self._rlimits = state['<STR_LIT>']<EOL>self.procs = state['<STR_LIT>']<EOL>self._current = state['<STR_LIT>']<EOL>self.running = state['<STR_LIT>']<EOL>self.rwait = state['<STR_LIT>']<EOL>self.twait = state['<STR_LIT>']<EOL>self.timers = state['<STR_LIT>']<EOL>self.clocks = state['<STR_LIT>']<EOL>self.syscall_trace = state['<STR_LIT>']<EOL>self.argv = state['<STR_LIT>']<EOL>self.envp = state['<STR_LIT>']<EOL>self.base = state['<STR_LIT>']<EOL>self.elf_bss = state['<STR_LIT>']<EOL>self.end_code = state['<STR_LIT>']<EOL>self.end_data = state['<STR_LIT>']<EOL>self.elf_brk = state['<STR_LIT>']<EOL>self.brk = state['<STR_LIT>']<EOL>self.auxv = state['<STR_LIT>']<EOL>self.program = state['<STR_LIT>']<EOL>self._function_abi = state['<STR_LIT>']<EOL>self._syscall_abi = state['<STR_LIT>']<EOL>self._uname_machine = state['<STR_LIT>']<EOL>if '<STR_LIT>' in state:<EOL><INDENT>self._arm_tls_memory = state['<STR_LIT>']<EOL><DEDENT>for proc in self.procs:<EOL><INDENT>self.forward_events_from(proc)<EOL><DEDENT>

:todo: some asserts
:todo: fix deps? (last line)


page_data = bytearray(b'<STR_LIT>' * <NUM_LIT>)<EOL>preamble = binascii.unhexlify(<EOL>'<STR_LIT>' +<EOL>'<STR_LIT>' +<EOL>'<STR_LIT>' +<EOL>'<STR_LIT>' +<EOL>'<STR_LIT>' +<EOL>'<STR_LIT>' +<EOL>'<STR_LIT>' +<EOL>'<STR_LIT>'<EOL>)<EOL>__kuser_cmpxchg64 = binascii.unhexlify(<EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>'   <EOL>)<EOL>__kuser_dmb = binascii.unhexlify(<EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>'   <EOL>)<EOL>__kuser_cmpxchg = binascii.unhexlify(<EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>'   <EOL>)<EOL>self._arm_tls_memory = self.current.memory.mmap(None, <NUM_LIT:4>, '<STR_LIT>')<EOL>__kuser_get_tls = binascii.unhexlify(<EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>' +  <EOL>'<STR_LIT>'   <EOL>) + struct.pack('<STR_LIT>', self._arm_tls_memory)<EOL>tls_area = b'<STR_LIT:\x00>' * <NUM_LIT:12><EOL>version = struct.pack('<STR_LIT>', <NUM_LIT:5>)<EOL>def update(address, code):<EOL><INDENT>page_data[address:address + len(code)] = code<EOL><DEDENT>update(<NUM_LIT>, preamble)<EOL>update(<NUM_LIT>, __kuser_cmpxchg64)<EOL>update(<NUM_LIT>, __kuser_dmb)<EOL>update(<NUM_LIT>, __kuser_cmpxchg)<EOL>update(<NUM_LIT>, __kuser_get_tls)<EOL>update(<NUM_LIT>, tls_area)<EOL>update(<NUM_LIT>, version)<EOL>self.current.memory.mmap(<NUM_LIT>, len(page_data), '<STR_LIT>', page_data)<EOL>

ARM kernel helpers

https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt


cpu = self.current<EOL>cpu.STACK = self._stack_top<EOL>auxv = self.auxv<EOL>logger.debug("<STR_LIT>")<EOL>logger.debug(f"<STR_LIT>")<EOL>if envp:<EOL><INDENT>logger.debug("<STR_LIT>")<EOL>for e in envp:<EOL><INDENT>logger.debug(f"<STR_LIT>")<EOL><DEDENT><DEDENT>logger.debug("<STR_LIT>")<EOL>for name, val in auxv.items():<EOL><INDENT>logger.debug(f"<STR_LIT>")<EOL><DEDENT>argvlst = []<EOL>envplst = []<EOL>for evar in envp:<EOL><INDENT>cpu.push_bytes('<STR_LIT:\x00>')<EOL>envplst.append(cpu.push_bytes(evar))<EOL><DEDENT>for arg in argv:<EOL><INDENT>cpu.push_bytes('<STR_LIT:\x00>')<EOL>argvlst.append(cpu.push_bytes(arg))<EOL><DEDENT>for name, value in auxv.items():<EOL><INDENT>if hasattr(value, '<STR_LIT>'):<EOL><INDENT>cpu.push_bytes(value)<EOL>auxv[name] = cpu.STACK<EOL><DEDENT><DEDENT>auxvnames = {<EOL>'<STR_LIT>': <NUM_LIT:1>,  <EOL>'<STR_LIT>': <NUM_LIT:2>,  <EOL>'<STR_LIT>': <NUM_LIT:3>,  <EOL>'<STR_LIT>': <NUM_LIT:4>,  <EOL>'<STR_LIT>': <NUM_LIT:5>,  <EOL>'<STR_LIT>': <NUM_LIT:6>,  <EOL>'<STR_LIT>': <NUM_LIT:7>,  <EOL>'<STR_LIT>': <NUM_LIT:8>,  <EOL>'<STR_LIT>': <NUM_LIT:9>,  <EOL>'<STR_LIT>': <NUM_LIT:10>,  <EOL>'<STR_LIT>': <NUM_LIT:11>,  <EOL>'<STR_LIT>': <NUM_LIT:12>,  <EOL>'<STR_LIT>': <NUM_LIT>,  <EOL>'<STR_LIT>': <NUM_LIT>,  <EOL>'<STR_LIT>': <NUM_LIT>,  <EOL>'<STR_LIT>': <NUM_LIT:15>,  <EOL>'<STR_LIT>': <NUM_LIT:16>,  <EOL>'<STR_LIT>': <NUM_LIT>,  <EOL>'<STR_LIT>': <NUM_LIT>,  <EOL>'<STR_LIT>': <NUM_LIT>,  <EOL>'<STR_LIT>': <NUM_LIT>,  <EOL>'<STR_LIT>': <NUM_LIT>,  <EOL>'<STR_LIT>': <NUM_LIT:32>,  <EOL>'<STR_LIT>': <NUM_LIT>,  <EOL>}<EOL>cpu.push_int(<NUM_LIT:0>)<EOL>cpu.push_int(<NUM_LIT:0>)<EOL>for name, val in auxv.items():<EOL><INDENT>cpu.push_int(val)<EOL>cpu.push_int(auxvnames[name])<EOL><DEDENT>cpu.push_int(<NUM_LIT:0>)<EOL>for var in reversed(envplst):              <EOL><INDENT>cpu.push_int(var)<EOL><DEDENT>envp = cpu.STACK<EOL>cpu.push_int(<NUM_LIT:0>)<EOL>for arg in reversed(argvlst):              <EOL><INDENT>cpu.push_int(arg)<EOL><DEDENT>argv = cpu.STACK<EOL>cpu.push_int(len(argvlst))<EOL>

:param Cpu cpu: The cpu instance
:param argv: list of parameters for the program to execute.
:param envp: list of environment variables for the program to execute.

http://www.phrack.org/issues.html?issue=58&id=5#article
 position            content                     size (bytes) + comment
 ----------------------------------------------------------------------
 stack pointer ->  [ argc = number of args ]     4
                 [ argv[0] (pointer) ]         4   (program name)
                 [ argv[1] (pointer) ]         4
                 [ argv[..] (pointer) ]        4 * x
                 [ argv[n - 1] (pointer) ]     4
                 [ argv[n] (pointer) ]         4   (= NULL)

                 [ envp[0] (pointer) ]         4
                 [ envp[1] (pointer) ]         4
                 [ envp[..] (pointer) ]        4
                 [ envp[term] (pointer) ]      4   (= NULL)

                 [ auxv[0] (Elf32_auxv_t) ]    8
                 [ auxv[1] (Elf32_auxv_t) ]    8
                 [ auxv[..] (Elf32_auxv_t) ]   8
                 [ auxv[term] (Elf32_auxv_t) ] 8   (= AT_NULL vector)

                 [ padding ]                   0 - 16

                 [ argument ASCIIZ strings ]   >= 0
                 [ environment ASCIIZ str. ]   >= 0

 (0xbffffffc)      [ end marker ]                4   (= NULL)

 (0xc0000000)      < top of stack >              0   (virtual)
 ----------------------------------------------------------------------


<EOL>cpu = self.current<EOL>elf = self.elf<EOL>arch = self.arch<EOL>env = dict(var.split('<STR_LIT:=>') for var in env if '<STR_LIT:=>' in var)<EOL>addressbitsize = {'<STR_LIT>': <NUM_LIT:32>, '<STR_LIT>': <NUM_LIT:64>, '<STR_LIT>': <NUM_LIT:32>}[elf.get_machine_arch()]<EOL>logger.debug("<STR_LIT>", filename, arch)<EOL>assert elf.header.e_type in ['<STR_LIT>', '<STR_LIT>', '<STR_LIT>']<EOL>interpreter = None<EOL>for elf_segment in elf.iter_segments():<EOL><INDENT>if elf_segment.header.p_type != '<STR_LIT>':<EOL><INDENT>continue<EOL><DEDENT>interpreter_filename = elf_segment.data()[:-<NUM_LIT:1>]<EOL>logger.info(f'<STR_LIT>')<EOL>if os.path.exists(interpreter_filename.decode('<STR_LIT:utf-8>')):<EOL><INDENT>interpreter = ELFFile(open(interpreter_filename, '<STR_LIT:rb>'))<EOL><DEDENT>elif '<STR_LIT>' in env:<EOL><INDENT>for mpath in env['<STR_LIT>'].split("<STR_LIT::>"):<EOL><INDENT>interpreter_path_filename = os.path.join(mpath, os.path.basename(interpreter_filename))<EOL>logger.info(f"<STR_LIT>")<EOL>if os.path.exists(interpreter_path_filename):<EOL><INDENT>interpreter = ELFFile(open(interpreter_path_filename, '<STR_LIT:rb>'))<EOL>break<EOL><DEDENT><DEDENT><DEDENT>break<EOL><DEDENT>if interpreter is not None:<EOL><INDENT>assert interpreter.get_machine_arch() == elf.get_machine_arch()<EOL>assert interpreter.header.e_type in ['<STR_LIT>', '<STR_LIT>']<EOL><DEDENT>executable_stack = False<EOL>for elf_segment in elf.iter_segments():<EOL><INDENT>if elf_segment.header.p_type != '<STR_LIT>':<EOL><INDENT>continue<EOL><DEDENT>if elf_segment.header.p_flags & <NUM_LIT>:<EOL><INDENT>executable_stack = True<EOL><DEDENT>else:<EOL><INDENT>executable_stack = False<EOL><DEDENT>break<EOL><DEDENT>base = <NUM_LIT:0><EOL>elf_bss = <NUM_LIT:0><EOL>end_code = <NUM_LIT:0><EOL>end_data = <NUM_LIT:0><EOL>elf_brk = <NUM_LIT:0><EOL>self.load_addr = <NUM_LIT:0><EOL>for elf_segment in elf.iter_segments():<EOL><INDENT>if elf_segment.header.p_type != '<STR_LIT>':<EOL><INDENT>continue<EOL><DEDENT>align = <NUM_LIT>  <EOL>ELF_PAGEOFFSET = elf_segment.header.p_vaddr & (align - <NUM_LIT:1>)<EOL>flags = elf_segment.header.p_flags<EOL>memsz = elf_segment.header.p_memsz + ELF_PAGEOFFSET<EOL>offset = elf_segment.header.p_offset - ELF_PAGEOFFSET<EOL>filesz = elf_segment.header.p_filesz + ELF_PAGEOFFSET<EOL>vaddr = elf_segment.header.p_vaddr - ELF_PAGEOFFSET<EOL>memsz = cpu.memory._ceil(memsz)<EOL>if base == <NUM_LIT:0> and elf.header.e_type == '<STR_LIT>':<EOL><INDENT>assert vaddr == <NUM_LIT:0><EOL>if addressbitsize == <NUM_LIT:32>:<EOL><INDENT>base = <NUM_LIT><EOL><DEDENT>else:<EOL><INDENT>base = <NUM_LIT><EOL><DEDENT><DEDENT>perms = perms_from_elf(flags)<EOL>hint = base + vaddr<EOL>if hint == <NUM_LIT:0>:<EOL><INDENT>hint = None<EOL><DEDENT>logger.debug(f"<STR_LIT>")<EOL>base = cpu.memory.mmapFile(hint, memsz, perms, elf_segment.stream.name, offset) - vaddr<EOL>if self.load_addr == <NUM_LIT:0>:<EOL><INDENT>self.load_addr = base + vaddr<EOL><DEDENT>k = base + vaddr + filesz<EOL>if k > elf_bss:<EOL><INDENT>elf_bss = k<EOL><DEDENT>if (flags & <NUM_LIT:4>) and end_code < k:  <EOL><INDENT>end_code = k<EOL><DEDENT>if end_data < k:<EOL><INDENT>end_data = k<EOL><DEDENT>k = base + vaddr + memsz<EOL>if k > elf_brk:<EOL><INDENT>elf_brk = k<EOL><DEDENT><DEDENT>elf_entry = elf.header.e_entry<EOL>if elf.header.e_type == '<STR_LIT>':<EOL><INDENT>elf_entry += self.load_addr<EOL><DEDENT>entry = elf_entry<EOL>real_elf_brk = elf_brk<EOL>bytes_to_clear = elf_brk - elf_bss<EOL>if bytes_to_clear > <NUM_LIT:0>:<EOL><INDENT>logger.debug(f"<STR_LIT>")<EOL>cpu.write_bytes(elf_bss, '<STR_LIT:\x00>' * bytes_to_clear, force=True)<EOL><DEDENT>stack_size = <NUM_LIT><EOL>if addressbitsize == <NUM_LIT:32>:<EOL><INDENT>stack_top = <NUM_LIT><EOL><DEDENT>else:<EOL><INDENT>stack_top = <NUM_LIT><EOL><DEDENT>stack_base = stack_top - stack_size<EOL>stack = cpu.memory.mmap(stack_base, stack_size, '<STR_LIT>', name='<STR_LIT>') + stack_size<EOL>assert stack_top == stack<EOL>reserved = cpu.memory.mmap(base + vaddr + memsz, <NUM_LIT>, '<STR_LIT:U+0020>')<EOL>interpreter_base = <NUM_LIT:0><EOL>if interpreter is not None:<EOL><INDENT>base = <NUM_LIT:0><EOL>elf_bss = <NUM_LIT:0><EOL>end_code = <NUM_LIT:0><EOL>end_data = <NUM_LIT:0><EOL>elf_brk = <NUM_LIT:0><EOL>entry = interpreter.header.e_entry<EOL>for elf_segment in interpreter.iter_segments():<EOL><INDENT>if elf_segment.header.p_type != '<STR_LIT>':<EOL><INDENT>continue<EOL><DEDENT>align = <NUM_LIT>  <EOL>vaddr = elf_segment.header.p_vaddr<EOL>filesz = elf_segment.header.p_filesz<EOL>flags = elf_segment.header.p_flags<EOL>offset = elf_segment.header.p_offset<EOL>memsz = elf_segment.header.p_memsz<EOL>ELF_PAGEOFFSET = (vaddr & (align - <NUM_LIT:1>))<EOL>memsz = memsz + ELF_PAGEOFFSET<EOL>offset = offset - ELF_PAGEOFFSET<EOL>filesz = filesz + ELF_PAGEOFFSET<EOL>vaddr = vaddr - ELF_PAGEOFFSET<EOL>memsz = cpu.memory._ceil(memsz)<EOL>if base == <NUM_LIT:0> and interpreter.header.e_type == '<STR_LIT>':<EOL><INDENT>assert vaddr == <NUM_LIT:0><EOL>total_size = self._interp_total_size(interpreter)<EOL>base = stack_base - total_size<EOL><DEDENT>if base == <NUM_LIT:0>:<EOL><INDENT>assert vaddr == <NUM_LIT:0><EOL><DEDENT>perms = perms_from_elf(flags)<EOL>hint = base + vaddr<EOL>if hint == <NUM_LIT:0>:<EOL><INDENT>hint = None<EOL><DEDENT>base = cpu.memory.mmapFile(hint, memsz, perms, elf_segment.stream.name, offset)<EOL>base -= vaddr<EOL>logger.debug(<EOL>f"<STR_LIT>"<EOL>f"<STR_LIT>"<EOL>f"<STR_LIT>"<EOL>f"<STR_LIT>"<EOL>f"<STR_LIT>"<EOL>f"<STR_LIT>"<EOL>)<EOL>k = base + vaddr + filesz<EOL>if k > elf_bss:<EOL><INDENT>elf_bss = k<EOL><DEDENT>if (flags & <NUM_LIT:4>) and end_code < k:  <EOL><INDENT>end_code = k<EOL><DEDENT>if end_data < k:<EOL><INDENT>end_data = k<EOL><DEDENT>k = base + vaddr + memsz<EOL>if k > elf_brk:<EOL><INDENT>elf_brk = k<EOL><DEDENT><DEDENT>if interpreter.header.e_type == '<STR_LIT>':<EOL><INDENT>entry += base<EOL><DEDENT>interpreter_base = base<EOL>bytes_to_clear = elf_brk - elf_bss<EOL>if bytes_to_clear > <NUM_LIT:0>:<EOL><INDENT>logger.debug(f"<STR_LIT>")<EOL>cpu.write_bytes(elf_bss, '<STR_LIT:\x00>' * bytes_to_clear, force=True)<EOL><DEDENT><DEDENT>cpu.memory.munmap(reserved, <NUM_LIT>)<EOL>cpu.STACK = stack<EOL>cpu.PC = entry<EOL>logger.debug(f"<STR_LIT>")<EOL>logger.debug(f"<STR_LIT>")<EOL>logger.debug(f"<STR_LIT>")<EOL>logger.debug(f"<STR_LIT>")<EOL>for m in str(cpu.memory).split('<STR_LIT:\n>'):<EOL><INDENT>logger.debug(f"<STR_LIT>")<EOL><DEDENT>self.base = base<EOL>self.elf_bss = elf_bss<EOL>self.end_code = end_code<EOL>self.end_data = end_data<EOL>self.elf_brk = real_elf_brk<EOL>self.brk = real_elf_brk<EOL>at_random = cpu.push_bytes('<STR_LIT:A>' * <NUM_LIT:16>)<EOL>at_execfn = cpu.push_bytes(f'<STR_LIT>')<EOL>self.auxv = {<EOL>'<STR_LIT>': self.load_addr + elf.header.e_phoff,  <EOL>'<STR_LIT>': elf.header.e_phentsize,       <EOL>'<STR_LIT>': elf.header.e_phnum,           <EOL>'<STR_LIT>': cpu.memory.page_size,         <EOL>'<STR_LIT>': interpreter_base,             <EOL>'<STR_LIT>': elf.header.e_flags,           <EOL>'<STR_LIT>': elf_entry,                    <EOL>'<STR_LIT>': <NUM_LIT:1000>,                         <EOL>'<STR_LIT>': <NUM_LIT:1000>,                         <EOL>'<STR_LIT>': <NUM_LIT:1000>,                         <EOL>'<STR_LIT>': <NUM_LIT:1000>,                         <EOL>'<STR_LIT>': <NUM_LIT:100>,                          <EOL>'<STR_LIT>': <NUM_LIT:0>,                            <EOL>'<STR_LIT>': at_random,                    <EOL>'<STR_LIT>': at_execfn,                    <EOL>}<EOL>

Loads and an ELF program in memory and prepares the initial CPU state.
Creates the stack and loads the environment variables and the arguments in it.

:param filename: pathname of the file to be executed. (used for auxv)
:param list env: A list of env variables. (used for extracting vars that control ld behavior)
:raises error:
    - 'Not matching cpu': if the program is compiled for a different architecture
    - 'Not matching memory': if the program is compiled for a different address size
:todo: define va_randomize and read_implies_exec personality


if None in self.files:<EOL><INDENT>fd = self.files.index(None)<EOL>self.files[fd] = f<EOL><DEDENT>else:<EOL><INDENT>fd = len(self.files)<EOL>self.files.append(f)<EOL><DEDENT>return fd<EOL>

Adds a file descriptor to the current file descriptor list

:rtype: int
:param f: the file descriptor to add.
:return: the index of the file descriptor in the file descr. list


try:<EOL><INDENT>self.files[fd].close()<EOL>self._closed_files.append(self.files[fd])  <EOL>self.files[fd] = None<EOL><DEDENT>except IndexError:<EOL><INDENT>raise FdError(f"<STR_LIT>")<EOL><DEDENT>

Removes a file descriptor from the file descriptor list
:rtype: int
:param fd: the file descriptor to close.
:return: C{0} on success.


return self._open(self.files[fd])<EOL>

Duplicates a file descriptor
:rtype: int
:param fd: the file descriptor to duplicate.
:return: C{0} on success.


return fd >= <NUM_LIT:0> and fd < len(self.files) and self.files[fd] is not None<EOL>

Determines if the fd is within range and in the file descr. list
:param fd: the file descriptor to check.


def _transform_write_data(self, data: T) -> T:

return data<EOL>

Implement in subclass to transform data written by write(2)/writev(2)
Nop by default.


logger.debug(f"<STR_LIT>")<EOL>return os.umask(mask)<EOL>

umask - Set file creation mode mask
:param int mask: New mask


path_str = self.current.read_string(path)<EOL>logger.debug(f"<STR_LIT>")<EOL>try:<EOL><INDENT>os.chdir(path_str)<EOL>return <NUM_LIT:0><EOL><DEDENT>except OSError as e:<EOL><INDENT>return e.errno<EOL><DEDENT>

chdir - Change current working directory
:param int path: Pointer to path


try:<EOL><INDENT>current_dir = os.getcwd()<EOL>length = len(current_dir) + <NUM_LIT:1><EOL>if size > <NUM_LIT:0> and size < length:<EOL><INDENT>logger.info("<STR_LIT>"<EOL>"<STR_LIT>")<EOL>return -errno.ERANGE<EOL><DEDENT>if not self.current.memory.access_ok(slice(buf, buf + length), '<STR_LIT:w>'):<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return -errno.EFAULT<EOL><DEDENT>self.current.write_string(buf, current_dir)<EOL>logger.debug(f"<STR_LIT>")<EOL>return length<EOL><DEDENT>except OSError as e:<EOL><INDENT>return -e.errno<EOL><DEDENT>

getcwd - Get the current working directory
:param int buf: Pointer to dest array
:param size: size in bytes of the array pointed to by the buf
:return: buf (Success), or 0


def sys_lseek(self, fd, offset, whence):

signed_offset = self._to_signed_dword(offset)<EOL>try:<EOL><INDENT>return self._get_fd(fd).seek(signed_offset, whence)<EOL><DEDENT>except FdError as e:<EOL><INDENT>logger.info(("<STR_LIT>"<EOL>"<STR_LIT>"))<EOL>return -e.err<EOL><DEDENT>

lseek - reposition read/write file offset

The lseek() function repositions the file offset of the open file description associated
with the file descriptor fd to the argument offset according to the directive whence

:param fd: a valid file descriptor
:param offset: the offset in bytes
:param whence: SEEK_SET: The file offset is set to offset bytes.
               SEEK_CUR: The file offset is set to its current location plus offset bytes.
               SEEK_END: The file offset is set to the size of the file plus offset bytes.

:return: offset from file beginning, or EBADF (fd is not a valid file descriptor or is not open)


data: bytes = bytes()<EOL>cpu = self.current<EOL>if count != <NUM_LIT:0>:<EOL><INDENT>try:<EOL><INDENT>write_fd = self._get_fd(fd)<EOL><DEDENT>except FdError as e:<EOL><INDENT>logger.error(f"<STR_LIT>")<EOL>return -e.err<EOL><DEDENT>if buf not in cpu.memory or buf + count not in cpu.memory:<EOL><INDENT>logger.debug("<STR_LIT>")<EOL>return -errno.EFAULT<EOL><DEDENT>if fd > <NUM_LIT:2> and write_fd.is_full():<EOL><INDENT>cpu.PC -= cpu.instruction.size<EOL>self.wait([], [fd], None)<EOL>raise RestartSyscall()<EOL><DEDENT>data: MixedSymbolicBuffer = cpu.read_bytes(buf, count)<EOL>data: bytes = self._transform_write_data(data)<EOL>write_fd.write(data)<EOL>for line in data.split(b'<STR_LIT:\n>'):<EOL><INDENT>line = line.decode('<STR_LIT>')  <EOL>logger.debug(f"<STR_LIT>")<EOL><DEDENT>self.syscall_trace.append(("<STR_LIT>", fd, data))<EOL>self.signal_transmit(fd)<EOL><DEDENT>return len(data)<EOL>

write - send bytes through a file descriptor
          The write system call writes up to count bytes from the buffer pointed
          to by buf to the file descriptor fd. If count is zero, write returns 0
          and optionally sets *tx_bytes to zero.

          :param fd            a valid file descriptor
          :param buf           a memory buffer
          :param count         number of bytes to send
          :return: 0          Success
                    EBADF      fd is not a valid file descriptor or is not open.
                    EFAULT     buf or tx_bytes points to an invalid address.


return -errno.ENOSYS<EOL>

We don't support forking, but do return a valid error code to client binary.


filename = b'<STR_LIT>'<EOL>for i in range(<NUM_LIT:0>, <NUM_LIT:255>):<EOL><INDENT>c = Operators.CHR(self.current.read_int(buf + i, <NUM_LIT:8>))<EOL>if c == b'<STR_LIT:\x00>':<EOL><INDENT>break<EOL><DEDENT>filename += c<EOL><DEDENT>if os.access(filename, mode):<EOL><INDENT>return <NUM_LIT:0><EOL><DEDENT>else:<EOL><INDENT>return -<NUM_LIT:1><EOL><DEDENT>

Checks real user's permissions for a file
:rtype: int

:param buf: a buffer containing the pathname to the file to check its permissions.
:param mode: the access permissions to check.
:return:
    -  C{0} if the calling process can access the file in the desired mode.
    - C{-1} if the calling process can not access the file in the desired mode.


from datetime import datetime<EOL>def pad(s):<EOL><INDENT>return s + '<STR_LIT:\x00>' * (<NUM_LIT> - len(s))<EOL><DEDENT>now = datetime(<NUM_LIT>, <NUM_LIT:8>, <NUM_LIT>).strftime("<STR_LIT>")<EOL>info = (('<STR_LIT>', '<STR_LIT>'),<EOL>('<STR_LIT>', '<STR_LIT>'),<EOL>('<STR_LIT>', '<STR_LIT>'),<EOL>('<STR_LIT:version>', '<STR_LIT>' + now),<EOL>('<STR_LIT>', self._uname_machine),<EOL>('<STR_LIT>', '<STR_LIT>'))<EOL>uname_buf = '<STR_LIT>'.join(pad(pair[<NUM_LIT:1>]) for pair in info)<EOL>self.current.write_bytes(old_utsname, uname_buf)<EOL>return <NUM_LIT:0><EOL>

Writes system information in the variable C{old_utsname}.
:rtype: int
:param old_utsname: the buffer to write the system info.
:return: C{0} on success


if brk != <NUM_LIT:0> and brk > self.elf_brk:<EOL><INDENT>mem = self.current.memory<EOL>size = brk - self.brk<EOL>if brk > mem._ceil(self.brk):<EOL><INDENT>perms = mem.perms(self.brk - <NUM_LIT:1>)<EOL>addr = mem.mmap(mem._ceil(self.brk), size, perms)<EOL>if not mem._ceil(self.brk) == addr:<EOL><INDENT>logger.error(f"<STR_LIT>")<EOL>return self.brk<EOL><DEDENT><DEDENT>self.brk += size<EOL><DEDENT>return self.brk<EOL>

Changes data segment size (moves the C{brk} to the new address)
:rtype: int
:param brk: the new address for C{brk}.
:return: the value of the new C{brk}.
:raises error:
            - "Error in brk!" if there is any error allocating the memory


ARCH_SET_GS = <NUM_LIT><EOL>ARCH_SET_FS = <NUM_LIT><EOL>ARCH_GET_FS = <NUM_LIT><EOL>ARCH_GET_GS = <NUM_LIT><EOL>if code not in {ARCH_SET_GS, ARCH_SET_FS, ARCH_GET_FS, ARCH_GET_GS}:<EOL><INDENT>logger.debug("<STR_LIT>")<EOL>return -errno.EINVAL<EOL><DEDENT>if code != ARCH_SET_FS:<EOL><INDENT>raise NotImplementedError("<STR_LIT>")<EOL><DEDENT>self.current.FS = <NUM_LIT><EOL>self.current.set_descriptor(self.current.FS, addr, <NUM_LIT>, '<STR_LIT>')<EOL>return <NUM_LIT:0><EOL>

Sets architecture-specific thread state
:rtype: int

:param code: must be C{ARCH_SET_FS}.
:param addr: the base address of the FS segment.
:return: C{0} on success
:raises error:
    - if C{code} is different to C{ARCH_SET_FS}


filename = self.current.read_string(buf)<EOL>try:<EOL><INDENT>f = self._sys_open_get_file(filename, flags)<EOL>logger.debug(f"<STR_LIT>")<EOL><DEDENT>except IOError as e:<EOL><INDENT>logger.warning(f"<STR_LIT>")<EOL>return -e.errno if e.errno is not None else -errno.EINVAL<EOL><DEDENT>return self._open(f)<EOL>

:param buf: address of zero-terminated pathname
:param flags: file access bits
:param mode: file permission mode


def sys_openat(self, dirfd, buf, flags, mode):

filename = self.current.read_string(buf)<EOL>dirfd = ctypes.c_int32(dirfd).value<EOL>if os.path.isabs(filename) or dirfd == self.FCNTL_FDCWD:<EOL><INDENT>return self.sys_open(buf, flags, mode)<EOL><DEDENT>try:<EOL><INDENT>dir_entry = self._get_fd(dirfd)<EOL><DEDENT>except FdError as e:<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return -e.err<EOL><DEDENT>if not isinstance(dir_entry, Directory):<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return -errno.ENOTDIR<EOL><DEDENT>dir_path = dir_entry.name<EOL>filename = os.path.join(dir_path, filename)<EOL>try:<EOL><INDENT>f = self._sys_open_get_file(filename, flags)<EOL>logger.debug(f"<STR_LIT>")<EOL><DEDENT>except IOError as e:<EOL><INDENT>logger.info(f"<STR_LIT>")<EOL>return -e.errno if e.errno is not None else -errno.EINVAL<EOL><DEDENT>return self._open(f)<EOL>

Openat SystemCall - Similar to open system call except dirfd argument
when path contained in buf is relative, dirfd is referred to set the relative path
Special value AT_FDCWD set for dirfd to set path relative to current directory

:param dirfd: directory file descriptor to refer in case of relative path at buf
:param buf: address of zero-terminated pathname
:param flags: file access bits
:param mode: file permission mode


def sys_rename(self, oldnamep, newnamep):

oldname = self.current.read_string(oldnamep)<EOL>newname = self.current.read_string(newnamep)<EOL>ret = <NUM_LIT:0><EOL>try:<EOL><INDENT>os.rename(oldname, newname)<EOL><DEDENT>except OSError as e:<EOL><INDENT>ret = -e.errno<EOL><DEDENT>return ret<EOL>

Rename filename `oldnamep` to `newnamep`.

:param int oldnamep: pointer to oldname
:param int newnamep: pointer to newname


ret = <NUM_LIT:0><EOL>try:<EOL><INDENT>self.files[fd].sync()<EOL><DEDENT>except IndexError:<EOL><INDENT>ret = -errno.EBADF<EOL><DEDENT>except FdError:<EOL><INDENT>ret = -errno.EINVAL<EOL><DEDENT>return ret<EOL>

Synchronize a file's in-core state with that on disk.


def sys_rt_sigaction(self, signum, act, oldact):

return self.sys_sigaction(signum, act, oldact)<EOL>


def sys_rt_sigprocmask(self, cpu, how, newset, oldset):

return self.sys_sigprocmask(cpu, how, newset, oldset)<EOL>


if not self._is_fd_open(fd):<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return -errno.EBADF<EOL><DEDENT>newfd = self._dup(fd)<EOL>return newfd<EOL>

Duplicates an open file descriptor
:rtype: int
:param fd: the open file descriptor to duplicate.
:return: the new file descriptor.


try:<EOL><INDENT>file = self._get_fd(fd)<EOL><DEDENT>except FdError as e:<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return -e.err<EOL><DEDENT>soft_max, hard_max = self._rlimits[self.RLIMIT_NOFILE]<EOL>if newfd >= soft_max:<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return -errno.EBADF<EOL><DEDENT>if self._is_fd_open(newfd):<EOL><INDENT>self._close(newfd)<EOL><DEDENT>if newfd >= len(self.files):<EOL><INDENT>self.files.extend([None] * (newfd + <NUM_LIT:1> - len(self.files)))<EOL><DEDENT>self.files[newfd] = self.files[fd]<EOL>logger.debug('<STR_LIT>', fd, newfd, newfd)<EOL>return newfd<EOL>

Duplicates an open fd to newfd. If newfd is open, it is first closed
:rtype: int
:param fd: the open file descriptor to duplicate.
:param newfd: the file descriptor to alias the file described by fd.
:return: newfd.


if path not in self.current.memory:<EOL><INDENT>return -errno.EFAULT<EOL><DEDENT>path_s = self.current.read_string(path)<EOL>if not os.path.exists(path_s):<EOL><INDENT>return -errno.ENOENT<EOL><DEDENT>if not os.path.isdir(path_s):<EOL><INDENT>return -errno.ENOTDIR<EOL><DEDENT>return -errno.EPERM<EOL>

An implementation of chroot that does perform some basic error checking,
but does not actually chroot.

:param path: Path to chroot


if self._is_fd_open(fd):<EOL><INDENT>self._close(fd)<EOL><DEDENT>else:<EOL><INDENT>return -errno.EBADF<EOL><DEDENT>logger.debug(f'<STR_LIT>')<EOL>return <NUM_LIT:0><EOL>

Closes a file descriptor
:rtype: int
:param fd: the file descriptor to close.
:return: C{0} on success.


def sys_readlink(self, path, buf, bufsize):

if bufsize <= <NUM_LIT:0>:<EOL><INDENT>return -errno.EINVAL<EOL><DEDENT>filename = self.current.read_string(path)<EOL>if filename == '<STR_LIT>':<EOL><INDENT>data = os.path.abspath(self.program)<EOL><DEDENT>else:<EOL><INDENT>data = os.readlink(filename)[:bufsize]<EOL><DEDENT>self.current.write_bytes(buf, data)<EOL>return len(data)<EOL>

Read
:rtype: int

:param path: the "link path id"
:param buf: the buffer where the bytes will be putted.
:param bufsize: the max size for read the link.
:todo: Out eax number of bytes actually sent | EAGAIN | EBADF | EFAULT | EINTR | errno.EINVAL | EIO | ENOSPC | EPIPE


def sys_mmap_pgoff(self, address, size, prot, flags, fd, offset):

return self.sys_mmap2(address, size, prot, flags, fd, offset)<EOL>


def sys_mmap2(self, address, size, prot, flags, fd, offset):

return self.sys_mmap(address, size, prot, flags, fd, offset * <NUM_LIT>)<EOL>

Creates a new mapping in the virtual address space of the calling process.
:rtype: int
:param address: the starting address for the new mapping. This address is used as hint unless the
                flag contains C{MAP_FIXED}.
:param size: the length of the mapping.
:param prot: the desired memory protection of the mapping.
:param flags: determines whether updates to the mapping are visible to other
              processes mapping the same region, and whether updates are carried
              through to the underlying file.
:param fd: the contents of a file mapping are initialized using C{size} bytes starting at
           offset C{offset} in the file referred to by the file descriptor C{fd}.
:param offset: the contents of a file mapping are initialized using C{size} bytes starting at
               offset C{offset}*0x1000 in the file referred to by the file descriptor C{fd}.
:return:
    - C{-1} In case you use C{MAP_FIXED} in the flags and the mapping can not be place at the desired address.
    - the address of the new mapping.


def sys_mmap(self, address, size, prot, flags, fd, offset):

if address == <NUM_LIT:0>:<EOL><INDENT>address = None<EOL><DEDENT>cpu = self.current<EOL>if flags & <NUM_LIT>:<EOL><INDENT>cpu.memory.munmap(address, size)<EOL><DEDENT>perms = perms_from_protflags(prot)<EOL>if flags & <NUM_LIT>:<EOL><INDENT>result = cpu.memory.mmap(address, size, perms)<EOL><DEDENT>elif fd == <NUM_LIT:0>:<EOL><INDENT>assert offset == <NUM_LIT:0><EOL>result = cpu.memory.mmap(address, size, perms)<EOL>data = self.files[fd].read(size)<EOL>cpu.write_bytes(result, data)<EOL><DEDENT>else:<EOL><INDENT>result = cpu.memory.mmapFile(address, size, perms, self.files[fd].name, offset)<EOL><DEDENT>actually_mapped = f'<STR_LIT>'<EOL>if address is None or result != address:<EOL><INDENT>address = address or <NUM_LIT:0><EOL>actually_mapped += f'<STR_LIT>'<EOL><DEDENT>if flags & <NUM_LIT> != <NUM_LIT:0> and result != address:<EOL><INDENT>cpu.memory.munmap(result, size)<EOL>result = -<NUM_LIT:1><EOL><DEDENT>return result<EOL>

Creates a new mapping in the virtual address space of the calling process.
:rtype: int

:param address: the starting address for the new mapping. This address is used as hint unless the
                flag contains C{MAP_FIXED}.
:param size: the length of the mapping.
:param prot: the desired memory protection of the mapping.
:param flags: determines whether updates to the mapping are visible to other
              processes mapping the same region, and whether updates are carried
              through to the underlying file.
:param fd: the contents of a file mapping are initialized using C{size} bytes starting at
           offset C{offset} in the file referred to by the file descriptor C{fd}.
:param offset: the contents of a file mapping are initialized using C{size} bytes starting at
               offset C{offset} in the file referred to by the file descriptor C{fd}.
:return:
        - C{-1} in case you use C{MAP_FIXED} in the flags and the mapping can not be place at the desired address.
        - the address of the new mapping (that must be the same as address in case you included C{MAP_FIXED} in flags).
:todo: handle exception.


def sys_mprotect(self, start, size, prot):

perms = perms_from_protflags(prot)<EOL>ret = self.current.memory.mprotect(start, size, perms)<EOL>return <NUM_LIT:0><EOL>

Sets protection on a region of memory. Changes protection for the calling process's
memory page(s) containing any part of the address range in the interval [C{start}, C{start}+C{size}-1].
:rtype: int

:param start: the starting address to change the permissions.
:param size: the size of the portion of memory to change the permissions.
:param prot: the new access permission for the memory.
:return: C{0} on success.


self.current.memory.munmap(addr, size)<EOL>return <NUM_LIT:0><EOL>

Unmaps a file from memory. It deletes the mappings for the specified address range
:rtype: int

:param addr: the starting address to unmap.
:param size: the size of the portion to unmap.
:return: C{0} on success.


return <NUM_LIT:1000><EOL>

Gets user identity.
:rtype: int

:return: this call returns C{1000} for all the users.


return <NUM_LIT:1000><EOL>

Gets group identity.
:rtype: int

:return: this call returns C{1000} for all the groups.


return <NUM_LIT:1000><EOL>

Gets user identity.
:rtype: int

:return: This call returns C{1000} for all the users.


return <NUM_LIT:1000><EOL>


cpu = self.current<EOL>ptrsize = cpu.address_bit_size<EOL>sizeof_iovec = <NUM_LIT:2> * (ptrsize // <NUM_LIT:8>)<EOL>total = <NUM_LIT:0><EOL>for i in range(<NUM_LIT:0>, count):<EOL><INDENT>buf = cpu.read_int(iov + i * sizeof_iovec, ptrsize)<EOL>size = cpu.read_int(iov + i * sizeof_iovec + (sizeof_iovec // <NUM_LIT:2>),<EOL>ptrsize)<EOL>data = self.files[fd].read(size)<EOL>total += len(data)<EOL>cpu.write_bytes(buf, data)<EOL>self.syscall_trace.append(("<STR_LIT>", fd, data))<EOL><DEDENT>return total<EOL>

Works just like C{sys_read} except that data is read into multiple buffers.
:rtype: int

:param fd: the file descriptor of the file to read.
:param iov: the buffer where the the bytes to read are stored.
:param count: amount of C{iov} buffers to read from the file.
:return: the amount of bytes read in total.


cpu = self.current<EOL>ptrsize = cpu.address_bit_size<EOL>sizeof_iovec = <NUM_LIT:2> * (ptrsize // <NUM_LIT:8>)<EOL>total = <NUM_LIT:0><EOL>try:<EOL><INDENT>write_fd = self._get_fd(fd)<EOL><DEDENT>except FdError as e:<EOL><INDENT>logger.error(f"<STR_LIT>")<EOL>return -e.err<EOL><DEDENT>for i in range(<NUM_LIT:0>, count):<EOL><INDENT>buf = cpu.read_int(iov + i * sizeof_iovec, ptrsize)<EOL>size = cpu.read_int(iov + i * sizeof_iovec + (sizeof_iovec // <NUM_LIT:2>), ptrsize)<EOL>data = [Operators.CHR(cpu.read_int(buf + i, <NUM_LIT:8>)) for i in range(size)]<EOL>data = self._transform_write_data(data)<EOL>write_fd.write(data)<EOL>self.syscall_trace.append(("<STR_LIT>", fd, data))<EOL>total += size<EOL><DEDENT>return total<EOL>

Works just like C{sys_write} except that multiple buffers are written out.
:rtype: int

:param fd: the file descriptor of the file to write.
:param iov: the buffer where the the bytes to write are taken.
:param count: amount of C{iov} buffers to write into the file.
:return: the amount of bytes written in total.


n = self.current.read_int(user_info, <NUM_LIT:32>)<EOL>pointer = self.current.read_int(user_info + <NUM_LIT:4>, <NUM_LIT:32>)<EOL>m = self.current.read_int(user_info + <NUM_LIT:8>, <NUM_LIT:32>)<EOL>flags = self.current.read_int(user_info + <NUM_LIT:12>, <NUM_LIT:32>)<EOL>assert n == <NUM_LIT><EOL>assert flags == <NUM_LIT>  <EOL>self.current.GS = <NUM_LIT><EOL>self.current.set_descriptor(self.current.GS, pointer, <NUM_LIT>, '<STR_LIT>')<EOL>self.current.write_int(user_info, (<NUM_LIT> - <NUM_LIT:3>) // <NUM_LIT:8>, <NUM_LIT:32>)<EOL>return <NUM_LIT:0><EOL>

Sets a thread local storage (TLS) area. Sets the base address of the GS segment.
:rtype: int

:param user_info: the TLS array entry set corresponds to the value of C{u_info->entry_number}.
:return: C{0} on success.


logger.warning("<STR_LIT>")<EOL>return <NUM_LIT:0><EOL>

System call ignored.
:rtype: int

:return: C{0}


def sys_setpriority(self, which, who, prio):


logger.debug("<STR_LIT>")<EOL>return -<NUM_LIT:1><EOL>

System call not implemented.
:rtype: int

:return: C{-1}


return self.sys_exit_group(error_code)<EOL>


return self._exit(f"<STR_LIT>")<EOL>

Exits all threads in a process
:raises Exception: 'Finished'


def sys_getrandom(self, buf, size, flags):

GRND_NONBLOCK = <NUM_LIT><EOL>GRND_RANDOM = <NUM_LIT><EOL>if size == <NUM_LIT:0>:<EOL><INDENT>return <NUM_LIT:0><EOL><DEDENT>if buf not in self.current.memory:<EOL><INDENT>logger.info("<STR_LIT>")<EOL>return -errno.EFAULT<EOL><DEDENT>if flags & ~(GRND_NONBLOCK | GRND_RANDOM):<EOL><INDENT>return -errno.EINVAL<EOL><DEDENT>self.current.write_bytes(buf, '<STR_LIT:\x00>' * size)<EOL>return size<EOL>

The getrandom system call fills the buffer with random bytes of buflen.
The source of random (/dev/random or /dev/urandom) is decided based on
the flags value.

Manticore's implementation simply fills a buffer with zeroes -- choosing
determinism over true randomness.

:param buf: address of buffer to be filled with random bytes
:param size: number of random bytes
:param flags: source of random (/dev/random or /dev/urandom)
:return: number of bytes copied to buf


index = self._syscall_abi.syscall_number()<EOL>try:<EOL><INDENT>table = getattr(linux_syscalls, self.current.machine)<EOL>name = table.get(index, None)<EOL>implementation = getattr(self, name)<EOL><DEDENT>except (AttributeError, KeyError):<EOL><INDENT>if name is not None:<EOL><INDENT>raise SyscallNotImplemented(index, name)<EOL><DEDENT>else:<EOL><INDENT>raise Exception(f"<STR_LIT>")<EOL><DEDENT><DEDENT>return self._syscall_abi.invoke(implementation)<EOL>


if len(self.procs) > <NUM_LIT:1>:<EOL><INDENT>logger.debug("<STR_LIT>")<EOL>logger.debug(f"<STR_LIT>")<EOL>logger.debug(f"<STR_LIT>")<EOL>logger.debug(f"<STR_LIT>")<EOL>logger.debug(f"<STR_LIT>")<EOL>logger.debug(f"<STR_LIT>")<EOL>logger.debug(f"<STR_LIT>")<EOL>logger.debug(f"<STR_LIT>")<EOL><DEDENT>if len(self.running) == <NUM_LIT:0>:<EOL><INDENT>logger.debug("<STR_LIT>")<EOL>if all([x is None for x in self.timers]):<EOL><INDENT>raise Deadlock()<EOL><DEDENT>self.clocks = min(x for x in self.timers if x is not None) + <NUM_LIT:1><EOL>self.check_timers()<EOL>assert len(self.running) != <NUM_LIT:0>, "<STR_LIT>"<EOL>self._current = self.running[<NUM_LIT:0>]<EOL>return<EOL><DEDENT>next_index = (self.running.index(self._current) + <NUM_LIT:1>) % len(self.running)<EOL>next_running_idx = self.running[next_index]<EOL>if len(self.procs) > <NUM_LIT:1>:<EOL><INDENT>logger.debug(f"<STR_LIT>")<EOL><DEDENT>self._current = next_running_idx<EOL>

Yield CPU.
            This will choose another process from the running list and change
            current running process. May give the same cpu if only one running
            process.