Implement logging presets (#445)

* logging template nits

* moved logging outside Manticore

* naming fix and exposed API call

* logging -> log renaming

* fix for verbosity test

* restored setter/getter for verbosity

* fixes for warnings in 0 mode and exteneed test_cli_verbosity

* removed print

* relative import, fork message to executor, init function

* verbosity docstring fix

* docstring nit
This commit is contained in:
Theofilos Petsios 2017-08-14 16:05:29 -04:00 committed by GitHub
parent 1d8e051522
commit 09bb702fac
6 changed files with 148 additions and 105 deletions

View File

@ -70,7 +70,6 @@ def main():
args = parse_arguments()
m = Manticore(args.programs[0], args.programs[1:])
m.policy = args.policy
m.args = args

View File

@ -315,6 +315,10 @@ class Executor(Eventful):
#Find a set of solutions for expression
solutions = state.concretize(expression, policy)
logger.info("Forking, about to store. (policy: %s, values: %s)",
policy,
', '.join('0x{:x}'.format(sol) for sol in solutions))
self.publish('will_fork_state', state, expression, solutions, policy)
#Build and enqueue a state for each solution
@ -334,7 +338,7 @@ class Executor(Eventful):
#maintain a list of childres for logging purpose
children.append(state_id)
logger.debug("Forking current state into states %r",children)
logger.debug("Forking current state into states %r", children)
return None
def run(self):

View File

@ -24,10 +24,10 @@ from .core.smtlib import solver, ConstraintSet
from .platforms import linux, decree, windows
from .utils.helpers import issymbolic
from .utils.nointerrupt import WithKeyboardInterruptAs
from .utils import log
logger = logging.getLogger('MANTICORE')
def makeDecree(program, concrete_data=''):
constraints = ConstraintSet()
platform = decree.SDecree(constraints, program)
@ -131,6 +131,7 @@ def binary_type(path):
else:
raise NotImplementedError("Binary {} not supported. Magic bytes: 0x{}".format(path, binascii.hexlify(magic)))
class Manticore(object):
'''
The central analysis object.
@ -170,7 +171,6 @@ class Manticore(object):
self._dumpafter = 0
self._maxstates = 0
self._maxstorage = 0
self._verbosity = 0
self._symbolic_files = [] # list of string
self._executor = None
#Executor wide shared context
@ -181,7 +181,7 @@ class Manticore(object):
if self._binary_type == 'ELF':
self._binary_obj = ELFFile(file(self._binary))
self._init_logging()
log.init_logging()
@property
def context(self):
@ -220,30 +220,6 @@ class Manticore(object):
yield ctx
context[key] = ctx
def _init_logging(self):
def loggerSetState(logger, stateid):
logger.filters[0].stateid = stateid
class ContextFilter(logging.Filter):
'''
This is a filter which injects contextual information into the log.
'''
def filter(self, record):
if hasattr(self, 'stateid') and isinstance(self.stateid, int):
record.stateid = '[%d]' % self.stateid
else:
record.stateid = ''
return True
ctxfilter = ContextFilter()
logging.basicConfig(format='%(asctime)s: [%(process)d]%(stateid)s %(name)s:%(levelname)s: %(message)s', stream=sys.stdout, level=logging.ERROR)
for loggername in ['MANTICORE', 'VISITOR', 'EXECUTOR', 'CPU', 'REGISTERS', 'SMT', 'MEMORY', 'PLATFORM']:
logging.getLogger(loggername).addFilter(ctxfilter)
logging.getLogger(loggername).setState = types.MethodType(loggerSetState, logging.getLogger(loggername))
# XXX(yan): args is a temporary hack to include while we continue moving
# non-Linux platforms to new-style arg handling.
@property
@ -290,40 +266,23 @@ class Manticore(object):
def maxstorage(self):
return self._maxstorage
@maxstorage.setter
def maxstorage(self, max_storage):
self._maxstorage = max_storage
@property
def verbosity(self):
'''
Convenience interface for setting logging verbosity to one of several predefined
logging presets. Valid values: 0-5
'''
return self._verbosity
"""Convenience interface for setting logging verbosity to one of
several predefined logging presets. Valid values: 0-5.
"""
return log.manticore_verbosity
@verbosity.setter
def verbosity(self, setting):
zero = map(lambda x: (x, logging.ERROR),
['MANTICORE', 'VISITOR', 'EXECUTOR', 'CPU', 'REGISTERS', 'SMT', 'MEMORY', 'PLATFORM'])
levels = [zero,
[('MANTICORE', logging.INFO), ('EXECUTOR', logging.INFO)],
[('PLATFORM', logging.DEBUG)],
[('MEMORY', logging.DEBUG), ('CPU', logging.DEBUG)],
[('REGISTERS', logging.DEBUG)],
[('SMT', logging.DEBUG)]]
"""A call used to modify the level of output verbosity
:param int setting: the level of verbosity to be used
"""
log.set_verbosity(setting)
# Takes a value and ensures it's in a certain range
def clamp(val, minimum, maximum):
return sorted((minimum, val, maximum))[1]
clamped = clamp(setting, 0, len(levels) - 1)
if clamped != setting:
logger.debug("%s not between 0 and %d, forcing to %d", setting, len(levels) - 1, clamped)
for level in range(clamped + 1):
for log_type, log_level in levels[level]:
logging.getLogger(log_type).setLevel(log_level)
self._verbosity = clamped
@maxstorage.setter
def maxstorage(self, max_storage):
self._maxstorage = max_storage
def hook(self, pc):
'''
@ -552,7 +511,7 @@ class Manticore(object):
def _terminate_state_callback(self, state, state_id, ex):
#aggregates state statistics into exceutor statistics. FIXME split
logger.info("Terminate state %r %r ", state, state_id)
logger.debug("Terminate state %r %r ", state, state_id)
if state is None:
return
state_visited = state.context.get('visited_since_last_fork', set())
@ -574,9 +533,6 @@ class Manticore(object):
manticore_context['visited'] = manticore_visited.union(state_visited)
state.context['visited_since_last_fork'] = set()
logger.info("Forking, about to store. (policy: %s, values: %s)", policy,
', '.join('0x{:x}'.format(pc) for pc in values))
def _read_register_callback(self, state, reg_name, value):
logger.debug("Read Register %r %r", reg_name, value)
@ -706,7 +662,6 @@ class Manticore(object):
ws_path = None
self._output = ManticoreOutput(ws_path)
self._executor = Executor(initial_state,
workspace=self._output.descriptor,
policy=self._policy,

View File

@ -1,4 +1,3 @@
import logging
import inspect

80
manticore/utils/log.py Normal file
View File

@ -0,0 +1,80 @@
import logging
import sys
import types
class ContextFilter(logging.Filter):
'''
This is a filter which injects contextual information into the log.
'''
def filter(self, record):
if hasattr(self, 'stateid') and isinstance(self.stateid, int):
record.stateid = '[%d]' % self.stateid
else:
record.stateid = ''
return True
loggers = ['MANTICORE',
'VISITOR',
'EXECUTOR',
'CPU',
'REGISTERS',
'SMT',
'MEMORY',
'PLATFORM']
manticore_verbosity = 0
def init_logging():
ctxfilter = ContextFilter()
logfmt = ("%(asctime)s: [%(process)d]%(stateid)s %(name)s:%(levelname)s:"
" %(message)s")
logging.basicConfig(format=logfmt, stream=sys.stdout, level=logging.ERROR)
for l in loggers:
logging.getLogger(l).setLevel(logging.WARNING)
logging.getLogger(l).addFilter(ctxfilter)
logging.getLogger(l).setState = types.MethodType(loggerSetState,
logging.getLogger(l))
def loggerSetState(logger, stateid):
logger.filters[0].stateid = stateid
def set_verbosity(setting):
global manticore_verbosity
zero = map(lambda x: (x, logging.WARNING), loggers)
levels = [
# 0
zero,
# 1
[
('MANTICORE', logging.INFO)
],
# 2 (-v)
[
('EXECUTOR', logging.INFO),
('PLATFORM', logging.DEBUG)
],
# 3 (-vv)
[
('CPU', logging.DEBUG)
],
# 4 (-vvv)
[
('MEMORY', logging.DEBUG),
('CPU', logging.DEBUG),
('REGISTERS', logging.DEBUG)
],
# 5 (-vvvv)
[
('MANTICORE', logging.DEBUG),
('SMT', logging.DEBUG)
]
]
# Takes a value and ensures it's in a certain range
def clamp(val, minimum, maximum):
return sorted((minimum, val, maximum))[1]
clamped = clamp(setting, 0, len(levels) - 1)
for level in range(clamped + 1):
for log_type, log_level in levels[level]:
logging.getLogger(log_type).setLevel(log_level)
manticore_verbosity = clamped

View File

@ -72,7 +72,13 @@ class IntegrationTest(unittest.TestCase):
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'binaries/basic_linux_amd64')
output = subprocess.check_output(['python', '-m', 'manticore', filename])
self.assertLessEqual(len(output.splitlines()), 25)
self.assertLessEqual(len(output.splitlines()), 60)
output = subprocess.check_output(['python', '-m', 'manticore', filename, "-v"])
self.assertLessEqual(len(output.splitlines()), 80)
output = subprocess.check_output(['python', '-m', 'manticore', filename, "-vvv"])
self.assertGreaterEqual(len(output.splitlines()), 435000)
output = subprocess.check_output(['python', '-m', 'manticore', filename, "-vvvv"])
self.assertGreaterEqual(len(output.splitlines()), 950000)
def testArgumentsAssertions(self):
dirname = os.path.dirname(__file__)