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

TUI Support Infrastructure #1620

Merged
merged 115 commits into from
Jan 27, 2021
Merged
Show file tree
Hide file tree
Changes from 111 commits
Commits
Show all changes
115 commits
Select commit Hold shift + click to select a range
a9cd665
Support for TUI (#1605)
pwang00 Feb 6, 2020
e0a0321
Add log monitoring
Mar 3, 2020
b090dad
Log monitoring via TCP
Mar 3, 2020
2620c8e
Swittch to rendering state lists directly
Mar 3, 2020
33116af
Extraneous line
Mar 3, 2020
beebf34
Merge branch 'master' into dev-phillip
Apr 10, 2020
9e70022
Switch log buffer to multiprocessing queue
Apr 10, 2020
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
284d84c
Merge branch 'master' into dev-phillip
Jul 22, 2020
57e6e62
Merge branch 'dev-introspection-api' into dev-phillip
Jul 22, 2020
3db977c
Add StateDescriptor to RTD
Jul 22, 2020
5fd0ad0
Add newlines for RTD parsing
Jul 22, 2020
7dec4ad
Update to work with new state introspection API
Jul 24, 2020
4e10256
Add termination messages
Jul 24, 2020
ea3a007
Also capture killed state messages
Jul 24, 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
b77ef2a
Merge branch 'dev-introspection-api' into dev-phillip
Aug 27, 2020
007fa85
Fix mypy errors
Aug 27, 2020
93c20fb
Make plugin logging even less verbose
Aug 27, 2020
dee36f0
Move log capture and state monitoring to daemon threads
Aug 28, 2020
c1e2936
Use the config module for host & port
Aug 28, 2020
ce3fbc3
Fix worker configuration and add test for TUI API
Aug 28, 2020
6ec8557
Fix log messages breaking native tests
Aug 28, 2020
ec0c595
Split up base Manticore tests and logging tests
Aug 28, 2020
8add055
Merge LogTCPHandler and MonitorTCPHandler
Aug 28, 2020
7a21ac5
Confirm that logging tests return to base level
Aug 28, 2020
68c08d3
Fix mypy
Aug 28, 2020
92c1630
Switch back to using a deque for log buffering in the default case
Aug 28, 2020
6d06fce
Fix deque API
Aug 28, 2020
b2a009a
Update state_pb2.py
Aug 28, 2020
617e23f
Reformat programatically generated files
Aug 28, 2020
4eb634b
Drop max verbosity in logging tests
Aug 28, 2020
ca17c3b
Merge branch 'master' into dev-phillip
Sep 22, 2020
14af4be
Merge branch 'master' into dev-phillip
Sep 22, 2020
42c4982
Fix duplicated code from bad merge
Sep 22, 2020
7605caa
Remove is_main from state_monitor
Oct 19, 2020
e41cf8c
Merge branch 'master' into dev-phillip
Jan 4, 2021
76e6bbd
Add comment about log buffer size
Jan 4, 2021
42bd3c8
Remove vestigial is_main
Jan 4, 2021
b1935ee
Blacken
Jan 5, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 38 additions & 7 deletions manticore/core/manticore.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import itertools
import logging
import sys
import time
import typing
import random
import weakref
Expand All @@ -21,11 +22,18 @@
from ..utils.deprecated import deprecated
from ..utils.enums import StateLists, MProcessingType
from ..utils.event import Eventful
from ..utils.helpers import PickleSerializer, pretty_print_state_descriptors
from ..utils.helpers import PickleSerializer, pretty_print_state_descriptors, deque
from ..utils.log import set_verbosity
from ..utils.nointerrupt import WithKeyboardInterruptAs
from .workspace import Workspace, Testcase
from .worker import WorkerSingle, WorkerThread, WorkerProcess, DaemonThread
from .worker import (
WorkerSingle,
WorkerThread,
WorkerProcess,
DaemonThread,
LogCaptureWorker,
state_monitor,
)

from multiprocessing.managers import SyncManager
import threading
Expand Down Expand Up @@ -88,6 +96,7 @@ def wait_for(self, condition, *args, **kwargs):
self._terminated_states = []
self._busy_states = []
self._killed_states = []
self._log_queue = deque(maxlen=5000)
self._shared_context = {}

def _manticore_threading(self):
Expand All @@ -99,6 +108,7 @@ def _manticore_threading(self):
self._terminated_states = []
self._busy_states = []
self._killed_states = []
self._log_queue = deque(maxlen=5000)
self._shared_context = {}

def _manticore_multiprocessing(self):
Expand All @@ -120,6 +130,7 @@ def raise_signal():
self._terminated_states = self._manager.list()
self._busy_states = self._manager.list()
self._killed_states = self._manager.list()
self._log_queue = self._manager.Queue(15000)
ehennenfent marked this conversation as resolved.
Show resolved Hide resolved
self._shared_context = self._manager.dict()
self._context_value_types = {list: self._manager.list, dict: self._manager.dict}

Expand Down Expand Up @@ -371,8 +382,10 @@ def __init__(
# Workers will use manticore __dict__ So lets spawn them last
self._workers = [self._worker_type(id=i, manticore=self) for i in range(consts.procs)]

# We won't create the daemons until .run() is called
self._daemon_threads: typing.List[DaemonThread] = []
# Create log capture worker. We won't create the rest of the daemons until .run() is called
self._daemon_threads: typing.Dict[int, DaemonThread] = {
-1: LogCaptureWorker(id=-1, manticore=self)
}
self._daemon_callbacks: typing.List[typing.Callable] = []

self._snapshot = None
Expand Down Expand Up @@ -1103,21 +1116,27 @@ def run(self):
# User subscription to events is disabled from now on
self.subscribe = None

self.register_daemon(state_monitor)
self._daemon_threads[-1].start() # Start log capture worker

# Passing generators to callbacks is a bit hairy because the first callback would drain it if we didn't
# clone the iterator in event.py. We're preserving the old API here, but it's something to avoid in the future.
self._publish("will_run", self.ready_states)
self._running.value = True

# start all the workers!
for w in self._workers:
w.start()

# Create each daemon thread and pass it `self`
if not self._daemon_threads: # Don't recreate the threads if we call run multiple times
for i, cb in enumerate(self._daemon_callbacks):
for i, cb in enumerate(self._daemon_callbacks):
if (
i not in self._daemon_threads
): # Don't recreate the threads if we call run multiple times
dt = DaemonThread(
id=i, manticore=self
) # Potentially duplicated ids with workers. Don't mix!
self._daemon_threads.append(dt)
self._daemon_threads[dt.id] = dt
dt.start(cb)

# Main process. Lets just wait and capture CTRL+C at main
Expand Down Expand Up @@ -1174,6 +1193,17 @@ def finalize(self):
self.generate_testcase(state)
self.remove_all()

def wait_for_log_purge(self):
"""
If a client has accessed the log server, and there are still buffered logs,
waits up to 2 seconds for the client to retrieve the logs.
"""
if self._daemon_threads[-1].activated:
for _ in range(8):
if self._log_queue.empty():
break
time.sleep(0.25)

############################################################################
############################################################################
############################################################################
Expand All @@ -1189,6 +1219,7 @@ def save_run_data(self):
config.save(f)

logger.info("Results in %s", self._output.store.uri)
self.wait_for_log_purge()

def introspect(self) -> typing.Dict[int, StateDescriptor]:
"""
Expand Down
18 changes: 18 additions & 0 deletions manticore/core/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,24 @@ def get_state_descriptors(self) -> typing.Dict[int, StateDescriptor]:
out = context.copy() # TODO: is this necessary to break out of the lock?
return out

def did_kill_state_callback(self, state, ex: Exception):
"""
Capture other state-killing exceptions so we can get the corresponding message

:param state: State that was killed
:param ex: The exception w/ the termination message
"""
state_id = state.id
with self.locked_context("manticore_state", dict) as context:
if state_id not in context:
logger.warning(
"Caught killing of state %s, but failed to capture its initialization",
state_id,
)
context.setdefault(state_id, StateDescriptor(state_id=state_id)).termination_msg = repr(
ex
)

@property
def unique_name(self) -> str:
return IntrospectionAPIPlugin.NAME
31 changes: 31 additions & 0 deletions manticore/core/state.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
syntax = "proto3";

package mserialize;

message LogMessage{
string content = 1;
}

message State{

enum StateType{
READY = 0;
BUSY = 1;
KILLED = 2;
TERMINATED = 3;
}

int32 id = 2; // state ID
StateType type = 3; // Type of state
string reason = 4; // Reason for execution stopping
int32 num_executing = 5; // number of executing instructions
int32 wait_time = 6;
}

message StateList{
repeated State states = 7;
}

message MessageList{
repeated LogMessage messages = 8;
}
Loading