diff --git a/docs/api.rst b/docs/api.rst index 4e1b045..45cd312 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1,10 +1,29 @@ API === -.. module:: manticore + +This API is under active development, and should be considered unstable. + +Helpers +------- + +.. autofunction:: manticore.issymbolic Manticore --------- -.. autoclass:: Manticore +.. autoclass:: manticore.Manticore :members: + +State +----- + +.. autoclass:: manticore.core.state.State + :members: + +Cpu +--- + +.. autoclass:: manticore.core.cpu.abstractcpu.Cpu + :members: read_int, read_bytes, write_int, write_bytes, write_register, read_register, all_registers + diff --git a/manticore/core/cpu/abstractcpu.py b/manticore/core/cpu/abstractcpu.py index bcc16f3..21c9b73 100644 --- a/manticore/core/cpu/abstractcpu.py +++ b/manticore/core/cpu/abstractcpu.py @@ -128,19 +128,21 @@ class RegisterFile(object): ############################################################################ # Abstract cpu encapsulating common cpu methods used by models and executor. class Cpu(object): - def __init__(self, regfile, memory): - ''' - This is an abstract representation os a Cpu. Functionality common to all - subyacent architectures (and expected from users of a Cpu) should be here. + ''' + Base class for all Cpu architectures. Functionality common to all + architectures (and expected from users of a Cpu) should be here. - The following attributes need to be defined in any derived class - assert hasattr(self, 'arch') - assert hasattr(self, 'mode') - assert hasattr(self, 'max_instr_width') - assert hasattr(self, 'address_bit_size') - assert hasattr(self, 'pc_alias') - assert hasattr(self, 'stack_alias') - ''' + The following attributes need to be defined in any derived class + + - arch + - mode + - max_instr_width + - address_bit_size + - pc_alias + - stack_alias + ''' + + def __init__(self, regfile, memory): assert isinstance(regfile, RegisterFile) super(Cpu, self).__init__() self._regfile = regfile @@ -179,26 +181,28 @@ class Cpu(object): @property def all_registers(self): - ''' Returns the list of all register names for this CPU. - @rtype: tuple - @return: the list of register names for this CPU. + '''Returns all register names for this CPU. Any register returned can be accessed + via a `cpu.REG` convenience interface (e.g. `cpu.EAX`) for both reading and + writing. + + :return: valid register names + :rtype: tuple[str] ''' return self._regfile.all_registers - #this operates on names def write_register(self, register, value): - ''' A convenient method to write a register by name (this accepts alias) - @param register a register name as listed in all_registers - @param value a value - @return It will return the written value possibly croped + '''Dynamic interface for writing cpu registers + + :param str register: register name (as listed in `self.all_registers`) + :param value: register value ''' return self._regfile.write(register, value) def read_register(self, register): - ''' A convenient method to read a register by name (this accepts alias) - @param register a register name as listed in all_registers - @param value a value - @return It will return the written value possibly croped + '''Dynamic interface for reading cpu registers + + :param str register: register name (as listed in `self.all_registers`) + :return: register value ''' return self._regfile.read(register) @@ -225,11 +229,12 @@ class Cpu(object): def write_int(self, where, expr, size=None): ''' - Writes an integer value of C{size} bits to memory at address C{where}. - - @param where: the address in memory where to store the value. - @param expr: the value to store in memory. - @param size: the amount of bytes to write. + Writes int to memory + + :param int where: address to write to + :param expr: value to write + :type expr: int or BitVec + :param size: bit size of `expr` ''' if size is None: size = self.address_bit_size @@ -238,12 +243,12 @@ class Cpu(object): def read_int(self, where, size=None): ''' - Reads anm integuer value of C{size} bits from memory at address C{where}. + Reads int from memory - @rtype: int or L{BitVec} - @param where: the address to read from. - @param size: the number of bits to read. - @return: the value read. + :param int where: address to read from + :param size: number of bits to read + :return: the value read + :rtype: int or BitVec ''' if size is None: size = self.address_bit_size @@ -256,20 +261,23 @@ class Cpu(object): def write_bytes(self, where, data): ''' - Writes C{data} in the address C{where}. - - @param where: address to write the data C{data}. - @param data: the data to write in the address C{where}. + Write a concrete or symbolic (or mixed) buffer to memory + + :param int where: address to write to + :param data: data to write + :type data: str ''' for i in xrange(len(data)): self.write_int( where+i, Operators.ORD(data[i]), 8) def read_bytes(self, where, size): ''' - Writes C{data} in the address C{where}. - - @param where: address to read the data C{data} from. - @param size: number of bytes. + Reads from memory + + :param int where: address to read data from + :param int size: number of bytes + :return: data + :rtype: list[int or Expression] ''' result = [] for i in xrange(size): diff --git a/manticore/core/state.py b/manticore/core/state.py index 20a3048..3e684f0 100644 --- a/manticore/core/state.py +++ b/manticore/core/state.py @@ -9,6 +9,14 @@ class AbandonState(Exception): class State(object): + ''' + Representation of a unique program state/path. + + :param ConstraintSet constraints: Initial constraints on state + :param model: Initial constraints on state + :type model: Decree or Linux or Windows + ''' + # Class global counter _state_count = manager.Value('i', 0) _lock = manager.Lock() @@ -91,26 +99,23 @@ class State(object): self.constraints.add(constraint) def abandon(self): - '''Abandon the currently-active state + '''Abandon the currently-active state. - Note: This must be called from the Executor loop, or a user-provided - callback.''' + Note: This must be called from the Executor loop, or a :func:`~manticore.Manticore.hook`. + ''' raise AbandonState def new_symbolic_buffer(self, nbytes, **options): - '''Create and return a symbolic buffer of length |nbytes|. The buffer is + '''Create and return a symbolic buffer of length `nbytes`. The buffer is not written into State's memory; write it to the state's memory to introduce it into the program state. - Args: - nbytes - Length of the new buffer - options - Options to set on the returned expression. Valid options: - name -- The name to assign to the buffer (str) - cstring -- Whether or not to enforce that the buffer is a cstring + :param int nbytes: Length of the new buffer + :param str name: (keyword arg only) The name to assign to the buffer + :param bool cstring: (keyword arg only) Whether or not to enforce that the buffer is a cstring (i.e. no \0 bytes, except for the last byte). (bool) - Returns: - Expression representing the buffer. + :return: :class:`~manticore.core.smtlib.expression.Expression` representing the buffer. ''' name = options.get('name', 'buffer') expr = self.constraints.new_array(name=name, index_max=nbytes) @@ -123,17 +128,15 @@ class State(object): return expr def new_symbolic_value(self, nbits, label='val', taint=frozenset()): - '''Create and return a symbolic value that is |nbits| bits wide. Assign + '''Create and return a symbolic value that is `nbits` bits wide. Assign the value to a register or write it into the address space to introduce it into the program state. - Args: - nbits - The bitwidth of the value returned. - label - The label to assign to the value. - taint - A tuple or frozenset of values to use as taint identifiers. - - Returns: - Expression representing the value. + :param int nbits: The bitwidth of the value returned + :param str label: The label to assign to the value + :param taint: Taint identifier of this value + :type taint: tuple or frozenset + :return: :class:`~manticore.core.smtlib.expression.Expression` representing the value ''' assert nbits in (1, 4, 8, 16, 32, 64, 128, 256) expr = self.constraints.new_bitvec(nbits, name=label, taint=taint) @@ -143,15 +146,13 @@ class State(object): def symbolicate_buffer(self, data, label='INPUT', wildcard='+', string=False): '''Mark parts of a buffer as symbolic (demarked by the wildcard byte) - Args: - data -- The string to symbolicate. If no wildcard bytes are provided, + :param str data: The string to symbolicate. If no wildcard bytes are provided, this is the identity function on the first argument. - label -- The label to assign to the value - wildcard -- The byte that is considered a wildcard - string -- Ensure bytes returned can not be \0 + :param str label: The label to assign to the value + :param str wildcard: The byte that is considered a wildcard + :param bool string: Ensure bytes returned can not be \0 - Returns: - If data does not contain any wildcard bytes, data itself. Otherwise, + :return: If data does not contain any wildcard bytes, data itself. Otherwise, a list of values derived from data. Non-wildcard bytes are kept as is, wildcard bytes are replaced by Expression objects. ''' @@ -198,11 +199,25 @@ class State(object): return solver def solve_one(self, expr): - # type: (Expression) -> int + ''' + Concretize a symbolic :class:`~manticore.core.smtlib.expression.Expression` into + one solution. + + :param manticore.core.smtlib.Expression expr: Symbolic value to concretize + :return: Concrete value + :rtype: int + ''' return self._solver.get_value(self.constraints, expr) def solve_n(self, expr, nsolves=1, policy='minmax'): - # type: (Expression, int) -> list + ''' + Concretize a symbolic :class:`~manticore.core.smtlib.expression.Expression` into + `nsolves` solutions. + + :param manticore.core.smtlib.Expression expr: Symbolic value to concretize + :return: Concrete value + :rtype: list[int] + ''' return self._solver.get_all_values(self.constraints, expr, nsolves, silent=True) def record_branches(self, targets): diff --git a/manticore/manticore.py b/manticore/manticore.py index dac9224..cc7880c 100644 --- a/manticore/manticore.py +++ b/manticore/manticore.py @@ -295,11 +295,8 @@ class Manticore(object): @property def verbosity(self): ''' - Convenience property for controlling the logging verbosity to a number of presets - - :getter: Get current verbosity level - :setter: Set current verbosity level [0-5] - :type: int + Convenience interface for setting logging verbosity to one of several predefined + logging presets. Valid values: 0-5 ''' return self._verbosity diff --git a/manticore/utils/helpers.py b/manticore/utils/helpers.py index 09e3344..47cf861 100644 --- a/manticore/utils/helpers.py +++ b/manticore/utils/helpers.py @@ -3,7 +3,12 @@ from ..core.smtlib import Expression def issymbolic(value): ''' - Helper to determine whether a value read is symbolic. + Helper to determine whether an object is symbolic (e.g checking + if data read from memory is symbolic) + + :param object value: object to check + :return: whether `value` is symbolic + :rtype: bool ''' return isinstance(value, Expression)