Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

State Introspection API #1775

Merged
merged 79 commits into from Sep 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
edd1cad
Create state transition events
Jul 16, 2020
9f45f21
Plug new events into context
Jul 16, 2020
dcc7774
move most enums to their own module
Jul 16, 2020
8c27091
Blacken
Jul 16, 2020
ae20d55
Add DaemonThread from TUI branch
Jul 16, 2020
4318c5c
Add interface for registering daemon threads
Jul 16, 2020
812e1dd
Timestamp StateDescriptor upon updates
Jul 16, 2020
1497345
Capture return value
Jul 17, 2020
f1db62b
Merge branch 'fix-run_dot_sh' into dev-introspection-api
Jul 17, 2020
7b3d0b4
Blacken
Jul 17, 2020
b28803a
Add solver wrapper to StateBase
Jul 17, 2020
3935f4e
Add `solve` events to all instances of SelectedSolver.instance()
Jul 17, 2020
51a0144
Remove executor constraints from WASM
Jul 17, 2020
2caa874
Add solve events to memory.py
Jul 17, 2020
4bcdbe3
Add intermittent execution event
Jul 18, 2020
c3c8866
Be more generous with states whose initialization we missed
Jul 18, 2020
572bb9f
Add Native callback for updating state descriptor
Jul 18, 2020
941c63a
Fix state killing
Jul 18, 2020
9a206e1
Blacken
Jul 18, 2020
09b4dcb
codecov: Remove outdated 'yml' entry in CI
ekilmer Jul 20, 2020
c2ebbb6
Add solve event to evm
Jul 18, 2020
4de43db
Drop solve events outside of a state context
Jul 20, 2020
228b1f8
Fix must/cannot_be_null usage
Jul 20, 2020
efba360
Fix missing solve event
Jul 20, 2020
064a9c9
Partially restore old did_fork_state ABI
Jul 20, 2020
8ceea6f
Called internally
Jul 20, 2020
0a5d371
Clone iterators instead of creating a list
Jul 21, 2020
cb7c940
Use isgenerator instead of checking if iterable
Jul 21, 2020
5b7c363
Fix snapshot restoration
Jul 21, 2020
5fcb64f
Slightly improve Unicorn test API usage
Jul 21, 2020
8356919
Temporarily disable property verifier tests
Jul 21, 2020
bf7bed9
improper skip arg
Jul 21, 2020
0b568d4
Add simple tests for introspection API
Jul 21, 2020
e5ef11a
Merge branch 'fixup-outdated-arg-codecov-ci' into dev-introspection-api
Jul 21, 2020
0ab1884
Add test for custom introspector, improve base introspection test
Jul 21, 2020
f7ccfde
Add intermittent update timestamp
Jul 21, 2020
2ec0973
Only allow daemon registration and introspection registration at init…
Jul 21, 2020
7132a4e
Add docs to manticore.py
Jul 21, 2020
623fbfe
Add docs for plugin, add update_state_descriptor to EVM
Jul 21, 2020
2657890
Fix renamed will_start_run --> will_run
Jul 21, 2020
42281fc
Docstrings for DaemonThread and EventSolver
Jul 21, 2020
fed14a0
Docs for enums
Jul 21, 2020
1ff6c54
Improve pretty printer, add some mypy fixes
Jul 21, 2020
39c497a
Don't run daemon threads if run is called multiple times
Jul 21, 2020
ddcb1d4
If at first you don't succeed, destroy all the evidence you tried.
Jul 21, 2020
ae01ebf
Test the pretty printer
Jul 22, 2020
3db977c
Add StateDescriptor to RTD
Jul 22, 2020
5fd0ad0
Add newlines for RTD parsing
Jul 22, 2020
4fcb088
Make info logs debug logs
Jul 24, 2020
6111f0d
Apply suggestions from code review
Jul 29, 2020
fbc6268
Add some type hints to manticore.py
Jul 29, 2020
c75893f
Add some type hints to plugin.py
Jul 29, 2020
6701cbf
Merge branch 'dev-introspection-api' of https://github.com/trailofbit…
Jul 29, 2020
9c4b496
Fix type hint for get_state
Jul 29, 2020
4368883
Add termination message from TUI PR
Jul 29, 2020
bed794d
Add example script
Jul 29, 2020
8cecb65
Add docstrings to the example script
Jul 29, 2020
4f8efd0
Pass introspection plugin type as an argument
Jul 30, 2020
bb9c877
Unskip property verifier tests
Aug 4, 2020
25f0efd
Merge branch 'master' into dev-introspection-api
Aug 4, 2020
36c6fbd
Add mypy-requests type hints
Aug 4, 2020
11404eb
Remove itertools.tee
Aug 5, 2020
34f5ecb
Merge branch 'master' into dev-introspection-api
Aug 5, 2020
201f585
Make generator cloning a little bit more robust
Aug 5, 2020
6be20b7
Clean up invalidated unit tests
Aug 5, 2020
c39f243
Debug missing Truffle & Examples coverage
Aug 10, 2020
b6f4112
Merge coverage from XML file
Aug 10, 2020
6517683
Switch coverage to JSON, ignore debug logging and NotImplemented code
Aug 10, 2020
eea716d
Fix copy commands
Aug 10, 2020
60620cb
Move .coverage files directly
Aug 10, 2020
1a44711
Set examples to append coverage
Aug 10, 2020
05629b8
FLAG_NAME doesn't work the way we'd like
Aug 10, 2020
a40b7a0
Merge branch 'master' into dev-introspection-api
Aug 26, 2020
8553caa
Use plugin dict to store introspector
Aug 26, 2020
46988dc
Appease mypy
Aug 26, 2020
a0239cc
Fix missing property on unique name
Aug 26, 2020
2c4471d
Grab EVM PC
Aug 26, 2020
c26f291
Blacken
Aug 26, 2020
905cd6c
Run black on all files if the git diff command fails
Aug 26, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions .coveragerc
Expand Up @@ -10,3 +10,10 @@ exclude_lines =

# Don't try to cover special syntax "..." in abstract class
@abstractmethod

# Ignore informational/debugging log statements
logger.info
logger.debug

# We don't bother testing code that's explicitly unimplemented
raise NotImplementedError
10 changes: 7 additions & 3 deletions .github/workflows/ci.yml
Expand Up @@ -29,7 +29,13 @@ jobs:
git fetch --depth=1 origin $BASE_SHA
echo "Files Changed:"
git diff --name-only $BASE_SHA... | tee .diff_names.txt
cat .diff_names.txt | python scripts/pyfile_exists.py | xargs black --diff --check
NAMES=$(cat .diff_names.txt | python scripts/pyfile_exists.py)
if test -z $NAMES
then
black --diff --check .
else
echo $NAMES | xargs black --diff --check
fi
mypy --version
mypy
tests:
Expand Down Expand Up @@ -103,5 +109,3 @@ jobs:
uses: pypa/gh-action-pypi-publish@v1.2.2
with:
password: ${{ secrets.PYPI_UPLOAD }}


8 changes: 8 additions & 0 deletions docs/states.rst
Expand Up @@ -16,3 +16,11 @@ Operations
:members:
:undoc-members:
:exclude-members: all_states, ready_states, count_ready_states, count_busy_states, killed_states, count_killed_states, terminated_states, count_terminated_states


Inspecting
----------

.. autoclass:: manticore.core.plugin.StateDescriptor
:members:
:undoc-members:
2 changes: 1 addition & 1 deletion examples/evm/mappingchallenge.py
Expand Up @@ -29,7 +29,7 @@
class StopAtDepth(Detector):
""" This just aborts explorations that are too deep """

def will_start_run_callback(self, *args):
def will_run_callback(self, *args):
with self.manticore.locked_context("seen_rep", dict) as reps:
reps.clear()

Expand Down
74 changes: 74 additions & 0 deletions examples/linux/introspect_state.py
@@ -0,0 +1,74 @@
from manticore.native import Manticore
from manticore.core.plugin import StateDescriptor
from manticore.utils.enums import StateStatus
from time import sleep
import typing
import argparse

parser = argparse.ArgumentParser(
description="Explore a binary with Manticore and print the tree of states"
)
parser.add_argument(
"binary", type=str, nargs="?", default="binaries/multiple-styles", help="The program to run",
)
args = parser.parse_args()


def print_fork_tree(states: typing.Dict[int, StateDescriptor]):
"""
Performs a depth-first traversal of the state tree, where each branch is a different fork
"""

def df_print(state_id, depth=0):
state = states[state_id]

# Prepare a debug message about the state based on its current status
msg = ""
if state.status == StateStatus.running:
msg = "(Exec {} ins)".format(state.own_execs if state.own_execs is not None else 0)
elif state.status == StateStatus.waiting_for_solver:
msg = "(Solving)"
elif state.status == StateStatus.waiting_for_worker:
msg = "(Waiting)"
elif state.status == StateStatus.stopped:
msg = "({})".format(state.termination_msg)

# Print nice pretty arrows showing parenthood
if depth == 0:
print(state_id, msg)
else:
print(" " * (depth - 1) + "└-->", state_id, msg)

# Prioritize states with fewer (or no) children since it gives us a nicer tree in the common case
for c_st in sorted(state.children, key=lambda k: len(states[k].children)):
df_print(c_st, depth + 1)

# Only works if all states fork from the initial state
df_print(0)
print()


def run_every(callee: typing.Callable, duration: int = 3) -> typing.Callable:
"""
Returns a function that calls <callee> every <duration> seconds
"""

def inner(thread): # Takes `thread` as argument, which is provided by the daemon thread API
while True:
# Pass Manticore's state descriptor dict to the callee
callee(thread.manticore.introspect())
sleep(duration)

return inner


m = Manticore(args.binary)

# Tell Manticore to run `print_fork_tree` every second
m.register_daemon(run_every(print_fork_tree, 1))

m.run()

sleep(1)
print("Final fork tree:")
print_fork_tree(m.introspect())