Fail* result browser for pruning experiments.
Based on the database layout given by the pruner. Run ./run.py -c <path to mysql.cnf> (Default config ~/.my.cnf) - Checks if objdump table exists - Added view for results per instruction - Added config file support for table details - Overview data loaded at server startup - Result type mapping configurable via config file Based on Flask and MySQLdb Change-Id: Ib49eac8f5c1e0ab23921aedb5bc53c34d0cde14d
This commit is contained in:
committed by
Gerrit Code Review
parent
b4f144745a
commit
e4bf980b97
19
tools/analysis/resultbrowser/README
Normal file
19
tools/analysis/resultbrowser/README
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Fail* Result Browser
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
* Python
|
||||||
|
* Flask (sudo pip install Flask)
|
||||||
|
* MySQLDB (sudo aptitude install python-mysqldb)
|
||||||
|
* YAML (sudo aptitude install python-yaml)
|
||||||
|
|
||||||
|
Based on Flask web microframework (Werkzeug, Jinja 2)
|
||||||
|
and old school MySQL bindings.
|
||||||
|
|
||||||
|
Connects to a Fail* result database given by a mysql config file.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
./run.py
|
||||||
|
Defaults to mysql config file ~/.my.cnf, or
|
||||||
|
./run.py -c <path to sqlconfig.cnf>
|
||||||
|
|
||||||
|
YAML based configuration for table and variant details.
|
||||||
4
tools/analysis/resultbrowser/app/__init__.py
Normal file
4
tools/analysis/resultbrowser/app/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
from flask import Flask
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
from app import views
|
||||||
143
tools/analysis/resultbrowser/app/data.py
Normal file
143
tools/analysis/resultbrowser/app/data.py
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
from pprint import pprint
|
||||||
|
import details
|
||||||
|
import model
|
||||||
|
|
||||||
|
def scrub(table_name):
|
||||||
|
return ''.join( chr for chr in table_name if chr.isalnum() or chr == '_' )
|
||||||
|
|
||||||
|
class Resulttype:
|
||||||
|
def __init__(self, name, count):
|
||||||
|
self.name = name
|
||||||
|
self.count = count
|
||||||
|
|
||||||
|
def getName(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def getCount(self):
|
||||||
|
return self.count
|
||||||
|
|
||||||
|
class Variant:
|
||||||
|
def __init__(self, id, name, table, benchmark, detail):
|
||||||
|
self.id = id
|
||||||
|
self.dbname = name
|
||||||
|
self.parenttable = table # TableDetails
|
||||||
|
self.details = detail # VariantDetails
|
||||||
|
self.benchmark = benchmark # BenchmarkDetails
|
||||||
|
self.results = {}
|
||||||
|
self.totalresults = 0
|
||||||
|
|
||||||
|
|
||||||
|
def getMapper(self):
|
||||||
|
mapper = self.benchmark.getMapper()
|
||||||
|
if not mapper: #try benchmark mapper
|
||||||
|
mapper = self.details.getMapper()
|
||||||
|
if not mapper: # of not there, try parent tables mapper
|
||||||
|
mapper = self.parenttable.getMapper()
|
||||||
|
if not mapper: # no mapper found at all, try default mapper
|
||||||
|
mapper = model.detaildealer.getDefaultMapper()
|
||||||
|
return mapper
|
||||||
|
|
||||||
|
|
||||||
|
def addResulttype(self, name, count):
|
||||||
|
mapper = self.getMapper()
|
||||||
|
label = mapper.getLabel(name)
|
||||||
|
oldcount = self.results.setdefault(label, 0)
|
||||||
|
self.results[label] = oldcount + count
|
||||||
|
self.totalresults += count
|
||||||
|
|
||||||
|
def getResultLabels(self):
|
||||||
|
return self.results.keys()
|
||||||
|
|
||||||
|
def getDBName(self):
|
||||||
|
return str(self.name)
|
||||||
|
|
||||||
|
def getId(self):
|
||||||
|
return self.id
|
||||||
|
|
||||||
|
def getResults(self):
|
||||||
|
return self.results
|
||||||
|
|
||||||
|
def getTableDetails(self):
|
||||||
|
return self.parenttable
|
||||||
|
|
||||||
|
def getBenchmarkDetails(self):
|
||||||
|
return self.benchmark
|
||||||
|
|
||||||
|
def getDetails(self):
|
||||||
|
return self.details
|
||||||
|
|
||||||
|
def getTotals(self):
|
||||||
|
return self.totalresults
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
ret = "Variant: " + self.getDetails().getTitle() + " - " + self.getBenchmarkDetails().getTitle() +" (id: " + str( self.id )+ ")" + " "
|
||||||
|
ret += "Total Results: " + str( self.totalresults ) + "\n"
|
||||||
|
for v in self.results:
|
||||||
|
ret += "\t" + v.name + ": " + str( v.count ) + "\n"
|
||||||
|
return ret
|
||||||
|
|
||||||
|
__repr__ = __str__
|
||||||
|
|
||||||
|
'''A ResultTable contains n Variants'''
|
||||||
|
class ResultTable:
|
||||||
|
|
||||||
|
def __init__(self, name, cfg):
|
||||||
|
self.name = scrub(name)
|
||||||
|
self.details = cfg.getTable(name)
|
||||||
|
self.variants = {}
|
||||||
|
|
||||||
|
def addVariant(self, var):
|
||||||
|
if var.getId() in self.variants:
|
||||||
|
return
|
||||||
|
self.variants[var.getId()] = var # Add if not existing yet
|
||||||
|
|
||||||
|
def getVariant(self, id):
|
||||||
|
if id in self.variants:
|
||||||
|
return self.variants[id]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def getVariantById(self, varid):
|
||||||
|
for k,v in self.variants.items():
|
||||||
|
if int(v.getId()) == int(varid):
|
||||||
|
return v
|
||||||
|
return None
|
||||||
|
|
||||||
|
def getDetails(self):
|
||||||
|
return self.details
|
||||||
|
|
||||||
|
def getVariants(self):
|
||||||
|
return self.variants
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
ret = "Result: " + self.getDetails().getTitle() + "\n"
|
||||||
|
for k,v in self.variants.items():
|
||||||
|
ret += "\t" + str(v) + "\n"
|
||||||
|
return ret
|
||||||
|
__repr__ = __str__
|
||||||
|
|
||||||
|
'''Overview has n ResultTables'''
|
||||||
|
class Overview:
|
||||||
|
def __init__(self):
|
||||||
|
self.tables = {}
|
||||||
|
|
||||||
|
def add(self, table):
|
||||||
|
self.tables[table.getDetails().getDBName()] = table
|
||||||
|
|
||||||
|
def getTables(self):
|
||||||
|
return self.tables
|
||||||
|
|
||||||
|
def getTable(self, dbname):
|
||||||
|
return self.tables.get(dbname, None)
|
||||||
|
|
||||||
|
def getVariantById(self, variant_id):
|
||||||
|
for key,table in self.tables.items():
|
||||||
|
variant = table.getVariantById(variant_id)
|
||||||
|
if variant:
|
||||||
|
return variant
|
||||||
|
print "Variant not found."
|
||||||
|
return None
|
||||||
|
|
||||||
|
def length(self):
|
||||||
|
return len(self.tables)
|
||||||
|
|
||||||
|
|
||||||
216
tools/analysis/resultbrowser/app/details.py
Normal file
216
tools/analysis/resultbrowser/app/details.py
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
|
||||||
|
class BasicDetails(object):
|
||||||
|
|
||||||
|
def __init__(self,name):
|
||||||
|
self.dbname = name
|
||||||
|
self.title = name
|
||||||
|
self.details = ''
|
||||||
|
self.mapper = None
|
||||||
|
|
||||||
|
def getDBName(self):
|
||||||
|
return self.dbname
|
||||||
|
|
||||||
|
def getDetails(self):
|
||||||
|
return self.details
|
||||||
|
|
||||||
|
def setDetails(self,det):
|
||||||
|
self.details = det
|
||||||
|
|
||||||
|
def getTitle(self):
|
||||||
|
return self.title
|
||||||
|
|
||||||
|
def addMapper(self, mapper):
|
||||||
|
self.mapper = mapper
|
||||||
|
|
||||||
|
def getMapper(self):
|
||||||
|
return self.mapper
|
||||||
|
|
||||||
|
def extractDetails(self, dictionary):
|
||||||
|
self.details = dictionary.pop(('details'), '')
|
||||||
|
self.title = dictionary.pop(('title'), self.dbname)
|
||||||
|
custommapping = dictionary.pop(('mapping'), None)
|
||||||
|
if custommapping:
|
||||||
|
self.mapper = ResulttypeMapper()
|
||||||
|
self.mapper.add(custommapping)
|
||||||
|
else:
|
||||||
|
self.mapper = None
|
||||||
|
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return self.getTitle() + ": " + self.getDetails()
|
||||||
|
|
||||||
|
|
||||||
|
__str__ = __repr__
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class BenchmarkDetails(BasicDetails):
|
||||||
|
|
||||||
|
def __init__(self, dbname):
|
||||||
|
BasicDetails.__init__(self, dbname)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "Benchmark: " + BasicDetails.__repr__(self)
|
||||||
|
|
||||||
|
__str__ = __repr__
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class VariantDetails(BasicDetails):
|
||||||
|
|
||||||
|
def __init__(self, dbname):
|
||||||
|
BasicDetails.__init__(self, dbname)
|
||||||
|
self.benchmarks = {}
|
||||||
|
|
||||||
|
def addBenchmark(self, bm):
|
||||||
|
self.benchmarks[bm.getDBName()] = bm
|
||||||
|
|
||||||
|
def getBenchmark(self, dbbm):
|
||||||
|
return self.benchmarks.get(dbbm, BenchmarkDetails(dbbm))
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
ret = "Variant: " + BasicDetails.__repr__(self)
|
||||||
|
for v in self.benchmarks.values():
|
||||||
|
ret += "\n\t\t" + str(v)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
__str__ = __repr__
|
||||||
|
|
||||||
|
class TableDetails(BasicDetails):
|
||||||
|
|
||||||
|
def __init__(self, tbl):
|
||||||
|
BasicDetails.__init__(self, tbl)
|
||||||
|
self.variants = {}
|
||||||
|
|
||||||
|
def addVariant(self, var):
|
||||||
|
self.variants[var.getDBName()] = var
|
||||||
|
|
||||||
|
def getVariant(self, varname):
|
||||||
|
return self.variants.get(varname, VariantDetails(varname))
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
ret = "Table: " + BasicDetails.__repr__(self) + "(" + self.getDBName() + ")"
|
||||||
|
for v in self.variants.values():
|
||||||
|
ret += "\n\t" + str(v)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
__str__ = __repr__
|
||||||
|
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
|
||||||
|
class ResulttypeMapper(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.mappings = {}
|
||||||
|
|
||||||
|
def add(self, mapping):
|
||||||
|
for label, dbnamelist in mapping.items():
|
||||||
|
self.mappings[label] = dbnamelist
|
||||||
|
|
||||||
|
def getLabel(self, dbname):
|
||||||
|
for label, dbnamelist in self.mappings.items():
|
||||||
|
if dbname in dbnamelist:
|
||||||
|
return label
|
||||||
|
return dbname
|
||||||
|
|
||||||
|
def getLabelList(self):
|
||||||
|
return self.mappings.keys()
|
||||||
|
|
||||||
|
def getDBNames(self, label):
|
||||||
|
return self.mappings.get(label, None)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
ret = "Resulttype Mapper:"
|
||||||
|
for label,dbnames in self.mappings.items():
|
||||||
|
ret += "\n\t" + label
|
||||||
|
for db in dbnames:
|
||||||
|
ret += "\n\t\t" + db
|
||||||
|
return ret
|
||||||
|
|
||||||
|
__str__ = __repr__
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
class DetailDealer:
|
||||||
|
|
||||||
|
def __init__(self, configfile=None):
|
||||||
|
self.tables = {}
|
||||||
|
self.defaultMapper = ResulttypeMapper()
|
||||||
|
|
||||||
|
if not configfile:
|
||||||
|
return
|
||||||
|
self.reload(configfile)
|
||||||
|
|
||||||
|
if not self.tables:
|
||||||
|
print "DetailDealer: no details found for " + configfile
|
||||||
|
|
||||||
|
def reload(self, configfile):
|
||||||
|
self.tables = {}
|
||||||
|
self.defaultMapper = ResulttypeMapper()
|
||||||
|
if not configfile:
|
||||||
|
return # no details.
|
||||||
|
f = open(configfile)
|
||||||
|
# use safe_load instead load
|
||||||
|
cfg = yaml.safe_load(f)
|
||||||
|
f.close()
|
||||||
|
# Read out default mapping, if existent
|
||||||
|
self.extractDefaults(cfg)
|
||||||
|
tables = cfg.pop('tables', None)
|
||||||
|
if tables:
|
||||||
|
for tablename,details in tables.items():
|
||||||
|
tab = TableDetails(tablename)
|
||||||
|
# pop: return and remove when key present, else return 'notfound'
|
||||||
|
tab.extractDetails(details)
|
||||||
|
variants = details.pop('variants')
|
||||||
|
for variantname, vdetails in variants.items():
|
||||||
|
var = VariantDetails(variantname)
|
||||||
|
var.extractDetails(vdetails)
|
||||||
|
benchmarks = vdetails.pop('benchmarks')
|
||||||
|
for benchmark, bdetails in benchmarks.items():
|
||||||
|
bm = BenchmarkDetails(benchmark)
|
||||||
|
bm.extractDetails(bdetails)
|
||||||
|
var.addBenchmark(bm)
|
||||||
|
tab.addVariant(var)
|
||||||
|
self.tables[tab.getDBName()] = (tab)
|
||||||
|
|
||||||
|
|
||||||
|
def extractDefaults(self, cfg):
|
||||||
|
defs = cfg.pop('defaults', None)
|
||||||
|
if defs:
|
||||||
|
defmap = defs.pop('mapping', None)
|
||||||
|
if defmap:
|
||||||
|
self.defaultMapper.add(defmap)
|
||||||
|
|
||||||
|
def getDefaultMapper(self):
|
||||||
|
return self.defaultMapper
|
||||||
|
|
||||||
|
def getTable(self, tablename):
|
||||||
|
tab = self.tables.get(tablename, None)
|
||||||
|
if tab:
|
||||||
|
return tab
|
||||||
|
return TableDetails(tablename)
|
||||||
|
|
||||||
|
def getVariant(self, tablename, variantname):
|
||||||
|
tab = self.getTable(tablename)
|
||||||
|
if tab:
|
||||||
|
return tab.getVariant(variantname)
|
||||||
|
return VariantDetails(variantname) # Default
|
||||||
|
|
||||||
|
def getBenchmark(self, table, variant, bechmark):
|
||||||
|
tab = self.getTable(table)
|
||||||
|
if tab:
|
||||||
|
var = tab.getVariant(variant)
|
||||||
|
if var:
|
||||||
|
return var.getBenchmark(bechmark)
|
||||||
|
return BenchmarkDetails(benchmark) # Default
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
ret = str(self.defaultMapper) + '\n'
|
||||||
|
for tabledetails in self.tables.values():
|
||||||
|
ret += str(tabledetails) + '\n'
|
||||||
|
return ret
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
dd = DetailDealer('./test.yml')
|
||||||
|
pprint(dd)
|
||||||
213
tools/analysis/resultbrowser/app/model.py
Executable file
213
tools/analysis/resultbrowser/app/model.py
Executable file
@ -0,0 +1,213 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
import MySQLdb
|
||||||
|
import MySQLdb.cursors
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
from pprint import pprint
|
||||||
|
import data
|
||||||
|
import details
|
||||||
|
|
||||||
|
"""Get command line options"""
|
||||||
|
from optparse import OptionParser
|
||||||
|
parser = OptionParser()
|
||||||
|
parser.add_option("-c", "--conf", type="string", help="MySQL config file", dest="config", default= os.path.join(os.path.expanduser("~"),".my.cnf"))
|
||||||
|
parser.add_option("-s", "--host", type="string", help="Webserver hostname", dest="host", default="localhost")
|
||||||
|
parser.add_option("-d", "--details", type="string", help="Detailed information (YAML configuration file)", dest="details", default=None)
|
||||||
|
parser.add_option("-p", "--port", type="string", help="Webserver port", dest="port", default="5000")
|
||||||
|
opts, args = parser.parse_args()
|
||||||
|
|
||||||
|
"""Check if configuration files exist"""
|
||||||
|
def checkConfigFile(msg, fname):
|
||||||
|
if not os.path.isfile(fname):
|
||||||
|
sys.exit("Error: '" + fname + "' not found")
|
||||||
|
else:
|
||||||
|
print msg, "->", fname
|
||||||
|
|
||||||
|
# Check sql config
|
||||||
|
sqlconfig = opts.config
|
||||||
|
checkConfigFile("MySQL config", sqlconfig)
|
||||||
|
|
||||||
|
# Check details file
|
||||||
|
if opts.details:
|
||||||
|
checkConfigFile("Details", opts.details)
|
||||||
|
|
||||||
|
# Instantiate global detail dealer, will be initialized in reloadOverview
|
||||||
|
detaildealer = details.DetailDealer()
|
||||||
|
|
||||||
|
|
||||||
|
"""Remove all characters from string except alphanuermics and _"""
|
||||||
|
def scrub(table_name):
|
||||||
|
return ''.join( chr for chr in table_name if chr.isalnum() or chr == '_' )
|
||||||
|
|
||||||
|
"""Global mysql handles"""
|
||||||
|
db = None
|
||||||
|
cur = None
|
||||||
|
def loadSession(dbconf):
|
||||||
|
global db
|
||||||
|
if db:
|
||||||
|
db.close()
|
||||||
|
db = MySQLdb.connect(read_default_file=dbconf, cursorclass=MySQLdb.cursors.DictCursor)
|
||||||
|
return db.cursor()
|
||||||
|
|
||||||
|
|
||||||
|
def closeSession():
|
||||||
|
if cur: cur.close()
|
||||||
|
global db
|
||||||
|
db.close()
|
||||||
|
db = None
|
||||||
|
|
||||||
|
|
||||||
|
'''Populate variant results for overview data'''
|
||||||
|
def getVariants(cur, table):
|
||||||
|
restbl = table.getDetails().getDBName()
|
||||||
|
cur.execute("""SELECT resulttype, variant, variant_id, benchmark, count(*) as total from %s join fsppilot on %s.pilot_id=fsppilot.id join variant on fsppilot.variant_id=variant.id group by resulttype, variant.id ORDER BY variant.id""" % (restbl, restbl)) # % is used here, as a tablename must not be quoted
|
||||||
|
res = cur.fetchall()
|
||||||
|
rdic = {}
|
||||||
|
# Build dict with variant id as key
|
||||||
|
for r in res:
|
||||||
|
# if variant entry already exists:
|
||||||
|
variant = table.getVariant(int(r['variant_id']))
|
||||||
|
if not variant: # if variant did not exist yet, create it:
|
||||||
|
variant_details = detaildealer.getVariant(restbl, r['variant'])
|
||||||
|
benchmark_details = detaildealer.getBenchmark(restbl, r['variant'], r['benchmark'])
|
||||||
|
table_details = detaildealer.getTable(restbl)
|
||||||
|
variant = data.Variant(int(r['variant_id']), r['variant'], table_details, benchmark_details, variant_details)
|
||||||
|
variant.addResulttype(r['resulttype'], r['total'])
|
||||||
|
table.addVariant(variant)
|
||||||
|
|
||||||
|
'''Get overview data for index page'''
|
||||||
|
def reloadOverview():
|
||||||
|
overview = data.Overview()
|
||||||
|
detaildealer.reload(opts.details)
|
||||||
|
cur = loadSession(sqlconfig)
|
||||||
|
cur.execute("show tables like 'result_%'")
|
||||||
|
result_tables = cur.fetchall()
|
||||||
|
results = {}
|
||||||
|
for rdic in result_tables:
|
||||||
|
# r is the tablename, -> result_FOOBAR
|
||||||
|
for key, tablename in rdic.items():
|
||||||
|
table = data.ResultTable(tablename,detaildealer)
|
||||||
|
getVariants(cur, table)
|
||||||
|
overview.add(table)
|
||||||
|
# Check if objdump table exists
|
||||||
|
cur.execute("SHOW TABLES like 'objdump'")
|
||||||
|
objdump_exists = (len(cur.fetchall()) == 1)
|
||||||
|
closeSession()
|
||||||
|
return overview, objdump_exists
|
||||||
|
|
||||||
|
"""Load overview data at server startup"""
|
||||||
|
print "Loading overview data from database. This may take a while ..."
|
||||||
|
overview_data, objdump_exists = reloadOverview()
|
||||||
|
print "done."
|
||||||
|
## Get overview data for views.index()
|
||||||
|
def getOverview():
|
||||||
|
return overview_data
|
||||||
|
|
||||||
|
def objdumpExists():
|
||||||
|
return objdump_exists
|
||||||
|
|
||||||
|
|
||||||
|
"""Get Results for one variant id"""
|
||||||
|
def getVariantResult(table, variantid):
|
||||||
|
cur = loadSession(sqlconfig)
|
||||||
|
restbl = scrub(table)
|
||||||
|
|
||||||
|
stmt = "SELECT resulttype, count(*) as total from %s join fsppilot on %s.pilot_id=fsppilot.id join variant on fsppilot.variant_id=variant.id" % (restbl, restbl)
|
||||||
|
where = " WHERE variant.id = %s group by resulttype ORDER BY resulttype"
|
||||||
|
stmt = stmt + where
|
||||||
|
cur.execute(stmt, variantid)
|
||||||
|
res = cur.fetchall()
|
||||||
|
closeSession()
|
||||||
|
return res
|
||||||
|
|
||||||
|
'''Show objdump together with according injection result types.'''
|
||||||
|
def getCode(result_table, variant_id, resultlabel=None):
|
||||||
|
result_table = scrub(result_table)
|
||||||
|
filt = ''
|
||||||
|
if not variant_id or not result_table:
|
||||||
|
return None
|
||||||
|
variant = overview_data.getVariantById(variant_id)
|
||||||
|
mapper = variant.getMapper()
|
||||||
|
if resultlabel:
|
||||||
|
dbnames = mapper.getDBNames(resultlabel)
|
||||||
|
if dbnames:
|
||||||
|
filt = " and ( "
|
||||||
|
for dbn in dbnames[:-1]:
|
||||||
|
filt += "resulttype = '" + dbn + "' OR "
|
||||||
|
filt += "resulttype = '" + dbnames[-1] +"' ) "
|
||||||
|
else:
|
||||||
|
filt = " and resulttype = '" + resultlabel + "' "
|
||||||
|
|
||||||
|
# I especially like this one:
|
||||||
|
select = "SELECT instr_address, opcode, disassemble, comment, COUNT(*) as totals, GROUP_CONCAT(DISTINCT resulttype SEPARATOR ', ') as results FROM %s " % result_table
|
||||||
|
join = "JOIN fsppilot ON pilot_id = fsppilot.id JOIN objdump ON objdump.instr_address = injection_instr_absolute "
|
||||||
|
where = "WHERE objdump.variant_id = %s AND fsppilot.variant_id = %s "
|
||||||
|
group = "GROUP BY injection_instr_absolute ORDER BY injection_instr_absolute "
|
||||||
|
|
||||||
|
cur = loadSession(sqlconfig)
|
||||||
|
stmt = select + join + where + filt + group
|
||||||
|
cur.execute(stmt, (variant_id, variant_id))
|
||||||
|
dump = cur.fetchall()
|
||||||
|
|
||||||
|
closeSession()
|
||||||
|
resulttypes = variant.getResultLabels()
|
||||||
|
return dump, resulttypes
|
||||||
|
|
||||||
|
def getCodeExcerpt(variant_id, instr_addr):
|
||||||
|
code = {}
|
||||||
|
limit = 4
|
||||||
|
cur = loadSession(sqlconfig)
|
||||||
|
cur.execute( """(SELECT instr_address, opcode, disassemble, comment FROM objdump \
|
||||||
|
WHERE instr_address < %s AND variant_id = %s \
|
||||||
|
ORDER BY instr_address DESC LIMIT %s) \
|
||||||
|
ORDER BY instr_address ASC""" , (instr_addr, variant_id, limit))
|
||||||
|
below = cur.fetchall()
|
||||||
|
code['below'] = below
|
||||||
|
cur.execute("""SELECT instr_address, opcode, disassemble, comment FROM objdump \
|
||||||
|
WHERE instr_address >= %s AND variant_id = %s \
|
||||||
|
ORDER BY instr_address ASC LIMIT %s""", (instr_addr, variant_id, limit+1))
|
||||||
|
upper = cur.fetchall()
|
||||||
|
code['upper'] = upper
|
||||||
|
closeSession()
|
||||||
|
return code
|
||||||
|
|
||||||
|
def getResultsbyInstruction(result_table, variant_id, instr_addr, resultlabel=None):
|
||||||
|
restypefilter = None
|
||||||
|
if resultlabel:
|
||||||
|
variant = overview_data.getVariantById(variant_id)
|
||||||
|
mapper = variant.getMapper()
|
||||||
|
if resultlabel:
|
||||||
|
dbnames = mapper.getDBNames(resultlabel)
|
||||||
|
if dbnames:
|
||||||
|
restypefilter = " and ( "
|
||||||
|
for dbn in dbnames[:-1]:
|
||||||
|
restypefilter += "resulttype = '" + dbn + "' OR "
|
||||||
|
restypefilter += "resulttype = '" + dbnames[-1] +"' ) "
|
||||||
|
|
||||||
|
|
||||||
|
#select = "SELECT data_address, data_width, original_value, bitoffset, experiment_number, details, resulttype from %s " % scrub(result_table)
|
||||||
|
select = "SELECT * from %s " % scrub(result_table)
|
||||||
|
join = "JOIN fsppilot ON pilot_id = fsppilot.id "
|
||||||
|
where = "WHERE variant_id = %s and injection_instr_absolute = %s "
|
||||||
|
order = "ORDER BY data_address, bitoffset"
|
||||||
|
|
||||||
|
cur = loadSession(sqlconfig)
|
||||||
|
if not restypefilter:
|
||||||
|
stmt = select + join + where + order
|
||||||
|
cur.execute(stmt, (variant_id, instr_addr))
|
||||||
|
else:
|
||||||
|
stmt = select + join + where + restypefilter + order
|
||||||
|
cur.execute(stmt, (variant_id, instr_addr))
|
||||||
|
|
||||||
|
res = cur.fetchall()
|
||||||
|
closeSession()
|
||||||
|
return res
|
||||||
|
|
||||||
|
def showDBstatus():
|
||||||
|
res = "TODO"
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
5
tools/analysis/resultbrowser/app/static/css/barchart.css
Normal file
5
tools/analysis/resultbrowser/app/static/css/barchart.css
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
dl.horizontal {font-size:12px; width:850px;}
|
||||||
|
dl.horizontal dt {float:left; width:300px; clear:both; margin:0 0 5px 0; padding:3px;}
|
||||||
|
dl.horizontal dd {float:left; width:500px; border:1px solid #aaaaaa; margin:0 0 5px 0; padding:2px; -moz-box-shadow: 1px 1px 3px #aaaaaa;}
|
||||||
|
dl.horizontal dd span {background:#91b4e6; display:block; color:black; text-indent:4px;}
|
||||||
|
|
||||||
214
tools/analysis/resultbrowser/app/static/css/main.css
Normal file
214
tools/analysis/resultbrowser/app/static/css/main.css
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:visited {
|
||||||
|
color : #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:link {
|
||||||
|
color : #444;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Create dark grey header with a white logo
|
||||||
|
*/
|
||||||
|
|
||||||
|
header {
|
||||||
|
background-color: #2B2B2B;
|
||||||
|
height: 30px;
|
||||||
|
width: 100%;
|
||||||
|
opacity: .9;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header h1.logo {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.5em;
|
||||||
|
color: #fff;
|
||||||
|
text-transform: uppercase;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
header h1.logo:hover {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Center the body content
|
||||||
|
*/
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 95%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.jumbo {
|
||||||
|
padding: 10px 0 30px 0;
|
||||||
|
background-color: #eeeeee;
|
||||||
|
-webkit-border-radius: 6px;
|
||||||
|
-moz-border-radius: 6px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.2em;
|
||||||
|
margin-top: 40px;
|
||||||
|
text-align: center;
|
||||||
|
letter-spacing: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 1.0em;
|
||||||
|
font-weight: 100;
|
||||||
|
margin-top: 30px;
|
||||||
|
text-align: center;
|
||||||
|
/*letter-spacing: -1px;*/
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#footer {
|
||||||
|
text-align: center;
|
||||||
|
color: #444;
|
||||||
|
font-size:10pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Table styles
|
||||||
|
*/
|
||||||
|
|
||||||
|
.codetable, .resulttable, .overviewtable{
|
||||||
|
font-family: monospace;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overviewtable {
|
||||||
|
border: 1px gray solid;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
.overviewtable tr:nth-child(4n), .overviewtable tr:nth-child(4n-1) {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.overviewtable tr:nth-child(4n-2), .overviewtable tr:nth-child(4n-3) {
|
||||||
|
background: #e8ffb3;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
.resulttable, .codetable, .overviewtable{
|
||||||
|
margin: auto;
|
||||||
|
border: solid #ccc 1px;
|
||||||
|
-moz-border-radius: 6px;
|
||||||
|
-webkit-border-radius: 6px;
|
||||||
|
border-radius: 6px;
|
||||||
|
-webkit-box-shadow: 0 1px 1px #ccc;
|
||||||
|
-moz-box-shadow: 0 1px 1px #ccc;
|
||||||
|
box-shadow: 0 1px 1px #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.codetable tr:hover, .resulttable tr:hover {
|
||||||
|
background: #fbf8e9;
|
||||||
|
/* -o-transition: all 0.1s ease-in-out;
|
||||||
|
-webkit-transition: all 0.1s ease-in-out;
|
||||||
|
-moz-transition: all 0.1s ease-in-out;
|
||||||
|
-ms-transition: all 0.1s ease-in-out;
|
||||||
|
transition: all 0.1s ease-in-out;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.resulttable td, .resulttable th, .codetable td, .codetable th {
|
||||||
|
border-left: none;
|
||||||
|
border-top: none;
|
||||||
|
padding: 2px;
|
||||||
|
text-align: left;
|
||||||
|
display: table-cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
.codetable td a {
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
padding: 0px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resulttable th, .codetable th, .overviewtable th {
|
||||||
|
background-color: #dce9f9;
|
||||||
|
background-image: -webkit-gradient(linear, left top, left bottom, from(#efe), to(#91b4e6));
|
||||||
|
background-image: -webkit-linear-gradient(top, #efe, #91b4e6);
|
||||||
|
background-image: -moz-linear-gradient(top, #efe, #91b4e6);
|
||||||
|
background-image: -ms-linear-gradient(top, #efe, #91b4e6);
|
||||||
|
background-image: -o-linear-gradient(top, #efe, #91b4e6);
|
||||||
|
background-image: linear-gradient(top, #efe, #91b4e6);
|
||||||
|
-webkit-box-shadow: 0 1px 0 rgba(255,255,255,.8) inset;
|
||||||
|
-moz-box-shadow:0 1px 0 rgba(255,255,255,.8) inset;
|
||||||
|
box-shadow: 0 1px 0 rgba(255,255,255,.8) inset;
|
||||||
|
border-top: none;
|
||||||
|
text-shadow: 0 1px 0 rgba(255,255,255,.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resulttable td:first-child, .resulttable th:first-child, .codetable td:first-child, .codetable th:first-child {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resulttable th:first-child, .codetable th:first-child {
|
||||||
|
-moz-border-radius: 6px 0 0 0;
|
||||||
|
-webkit-border-radius: 6px 0 0 0;
|
||||||
|
border-radius: 6px 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resulttable th:last-child, .codetable th:last-child {
|
||||||
|
-moz-border-radius: 0 6px 0 0;
|
||||||
|
-webkit-border-radius: 0 6px 0 0;
|
||||||
|
border-radius: 0 6px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resulttable th:only-child, .codetable th:only-child{
|
||||||
|
-moz-border-radius: 6px 6px 0 0;
|
||||||
|
-webkit-border-radius: 6px 6px 0 0;
|
||||||
|
border-radius: 6px 6px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resulttable tr:last-child td:first-child, .codetable tr:last-child td:first-child {
|
||||||
|
-moz-border-radius: 0 0 0 6px;
|
||||||
|
-webkit-border-radius: 0 0 0 6px;
|
||||||
|
border-radius: 0 0 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resulttable tr:last-child td:last-child, .codetable tr:last-child td:last-child {
|
||||||
|
-moz-border-radius: 0 0 6px 0;
|
||||||
|
-webkit-border-radius: 0 0 6px 0;
|
||||||
|
border-radius: 0 0 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resulttypemenu {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Display navigation links inline
|
||||||
|
*/
|
||||||
|
|
||||||
|
.menu {
|
||||||
|
float: right;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu li {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu li + li {
|
||||||
|
margin-left: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu li a {
|
||||||
|
color: #999;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
BIN
tools/analysis/resultbrowser/app/static/favicon.ico
Normal file
BIN
tools/analysis/resultbrowser/app/static/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
11
tools/analysis/resultbrowser/app/templates/about.html
Normal file
11
tools/analysis/resultbrowser/app/templates/about.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{% extends "layout.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% if status %}
|
||||||
|
<h2>About</h2>
|
||||||
|
{{ status }}
|
||||||
|
{% else %}
|
||||||
|
<h2> Sorry, no status information.</h2>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
50
tools/analysis/resultbrowser/app/templates/code.html
Normal file
50
tools/analysis/resultbrowser/app/templates/code.html
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
{% extends "layout.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>Variant Results</h1>
|
||||||
|
|
||||||
|
{% if resulttypes %}
|
||||||
|
<table>
|
||||||
|
<tr><td>Result Table</td><td><b>{{ variant_details.getTableDetails().getTitle() }}</b><td></tr>
|
||||||
|
<tr><td>Variant </td><td><b>{{ variant_details.getDetails().getTitle() }}</b></td></tr>
|
||||||
|
<tr><td>Details </td><td><b>{{ variant_details.getDetails().getDetails() }}</b></td></tr>
|
||||||
|
<tr><td>Benchmark </td><td><b>{{ variant_details.getBenchmarkDetails().getTitle() }}</b></td></tr>
|
||||||
|
<tr><td>Details </td><td><b>{{ variant_details.getBenchmarkDetails().getDetails() }}</b></td></tr>
|
||||||
|
<tr><td>Result Count </td><td><b>{{ results|length }}</b></td></tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<p class='resulttypemenu'>| <a href="{{ url_for('code', variant_id=request.args.get('variant_id'), table=request.args.get('table')) }}">All Results</a> |
|
||||||
|
{% for restype in resulttypes %}
|
||||||
|
<a href="{{ url_for('code', variant_id=request.args.get('variant_id'), table=request.args.get('table'), resulttype=restype )}}">{{ restype}}</a> |
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
<hr>
|
||||||
|
<table class="codetable">
|
||||||
|
<tr>
|
||||||
|
<th>Address</th>
|
||||||
|
<th>Opcode</th>
|
||||||
|
<th>Disassembly</th>
|
||||||
|
<th>Comment</th>
|
||||||
|
<th>Results</th>
|
||||||
|
<th># Results</th>
|
||||||
|
</tr>
|
||||||
|
{% for d in results %}
|
||||||
|
{% set link = url_for('instr_details', table=request.args.get('table'), variant_id=request.args.get('variant_id'), benchmark=request.args.get('benchmark'), variant=request.args.get('variant'), resulttype=request.args.get('resulttype'), instr_address=d['instr_address'] ) %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{{ link }}">{{ "0x%x"|format(d['instr_address']) }}</a></td>
|
||||||
|
<td><a href="{{ link }}">{{ d['opcode'] }}</a></td>
|
||||||
|
<td><a href="{{ link }}">{{ d['disassemble'] }}</a></td>
|
||||||
|
<td><a href="{{ link }}">{{ d['comment'] }}</a></td>
|
||||||
|
<td><a href="{{ link }}">{{ d['results'] }}</a></td>
|
||||||
|
<td><a href="{{ link }}">{{ d['totals'] }}</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<h1> Sorry, no dump found.</h1>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{%endblock %}
|
||||||
|
|
||||||
|
|
||||||
55
tools/analysis/resultbrowser/app/templates/index.html
Normal file
55
tools/analysis/resultbrowser/app/templates/index.html
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{% extends "layout.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{%if overview %}
|
||||||
|
{% for tablekey, resulttable in overview.getTables().items() %}
|
||||||
|
<h2>Result table: {{ resulttable.getDetails().getTitle() }}</h2>
|
||||||
|
-> <a href="{{ url_for('index', reload=1) }}">Reload data</a> <-
|
||||||
|
<dl>
|
||||||
|
<dt>Details:</td>
|
||||||
|
<dd>
|
||||||
|
{{ resulttable.getDetails().getDetails() }}
|
||||||
|
<dd>
|
||||||
|
</dl>
|
||||||
|
{% if not objdump_there %}
|
||||||
|
No objdump found
|
||||||
|
{% endif %}
|
||||||
|
<table class="overviewtable" cellspacing="0px">
|
||||||
|
{% for varid, variant in resulttable.getVariants().items() %}
|
||||||
|
<tr><th>
|
||||||
|
{% set variant_title=variant.getDetails().getTitle() ~ " - " ~ variant.getBenchmarkDetails().getTitle() ~ " id: " ~ variant.getId() %}
|
||||||
|
{% if objdump_there %}
|
||||||
|
<a href="{{ url_for('code',table=resulttable.getDetails().getDBName(), variant_id=variant.getId() ) }}">{{ variant_title }}</a>
|
||||||
|
{% else %}
|
||||||
|
{{ variant_title }}
|
||||||
|
{% endif %}
|
||||||
|
(Total: {{ variant.getTotals() }})</a>
|
||||||
|
</th></tr>
|
||||||
|
<tr><td>
|
||||||
|
{% if variant.getDetails().getDetails() %}
|
||||||
|
Variant Details: {{ variant.getDetails().getDetails() }}
|
||||||
|
{% endif %}
|
||||||
|
{% if variant.getBenchmarkDetails().getDetails() %}
|
||||||
|
<br> Benchmark Details: {{ variant.getBenchmarkDetails().getDetails() }}</td></tr>
|
||||||
|
{% endif %}
|
||||||
|
<tr><td>
|
||||||
|
<dl class="horizontal">
|
||||||
|
{% for reslabel,count in variant.getResults().items() %}
|
||||||
|
<dt>
|
||||||
|
{% if objdump_there %}
|
||||||
|
<a href="{{ url_for('code', table=resulttable.getDetails().getDBName(), variant_id=variant.getId(), resulttype=reslabel ) }}">{{ reslabel }}</a>
|
||||||
|
{% else %}
|
||||||
|
{{ reslabel }}
|
||||||
|
{% endif %}
|
||||||
|
</dt>
|
||||||
|
<dd><span style="width:{{count * 100 / variant.getTotals() }}%;">{{count}}</span></dd>
|
||||||
|
{% endfor %}
|
||||||
|
</dl></td></tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<h2> Sorry, no results found.</h2>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
{% extends "layout.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% if code %}
|
||||||
|
<h1>Result by Instruction</h1>
|
||||||
|
<table>
|
||||||
|
<tr><td>Result Table</td><td><b>{{ variant_details.getTableDetails().getTitle() }}</b><td></tr>
|
||||||
|
<tr><td>Variant </td><td><b>{{ variant_details.getDetails().getTitle() }}</b></td></tr>
|
||||||
|
<tr><td>Benchmark </td><td><b>{{ variant_details.getBenchmarkDetails().getTitle() }}</b></td></tr>
|
||||||
|
<tr><td>Details </td><td><b>{{ variant_details.getDetails().getDetails() }}</b></td></tr>
|
||||||
|
<tr><td>Instruction Address </td><td><b>{{ "0x%x (Dec: %d)"|format(request.args.get('instr_address')|int, request.args.get('instr_address')|int) }}</b></td></tr>
|
||||||
|
<tr><td>Total Results</td><td><b>{{ result|length }}</b></td></tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<h2>Code</h2>
|
||||||
|
<table class="codetable">
|
||||||
|
<tr>
|
||||||
|
<th>Address</th>
|
||||||
|
<th>Opcode</th>
|
||||||
|
<th>Disassembly</th>
|
||||||
|
<th>Comment</th>
|
||||||
|
</tr>
|
||||||
|
{% for d in code['below'] %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ "0x%x"|format(d['instr_address']) }}</td>
|
||||||
|
<td>{{ d['opcode'] }}</td>
|
||||||
|
<td>{{ d['disassemble'] }}</td>
|
||||||
|
<td>{{ d['comment'] }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
<tr style="font-weight: bold">
|
||||||
|
<td>{{ "0x%x"|format(code['upper'][0]['instr_address']) }}</td>
|
||||||
|
<td>{{ code['upper'][0]['opcode'] }}</td>
|
||||||
|
<td>{{ code['upper'][0]['disassemble'] }}</td>
|
||||||
|
<td>{{ code['upper'][0]['comment'] }}</td>
|
||||||
|
</tr>
|
||||||
|
{% for d in code['upper'][1:] %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ "0x%x"|format(d['instr_address']) }}</td>
|
||||||
|
<td>{{ d['opcode'] }}</td>
|
||||||
|
<td>{{ d['disassemble'] }}</td>
|
||||||
|
<td>{{ d['comment'] }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}</table>
|
||||||
|
<hr>
|
||||||
|
<h2>Results ({{ result|length }})</h2>
|
||||||
|
<table class="resulttable">
|
||||||
|
<tr>
|
||||||
|
{% for key, value in result[0].items() -%}
|
||||||
|
<th>{{ key }}</th>
|
||||||
|
{% endfor -%}
|
||||||
|
</tr>
|
||||||
|
{% for r in result -%}
|
||||||
|
<tr>
|
||||||
|
{% for k,v in r.items() -%}
|
||||||
|
<td>{{ v }}</td>
|
||||||
|
{% endfor -%}
|
||||||
|
</tr>
|
||||||
|
{% endfor -%}
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<h2> Sorry, no details found.</h2>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
32
tools/analysis/resultbrowser/app/templates/layout.html
Normal file
32
tools/analysis/resultbrowser/app/templates/layout.html
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Fail* Results</title>
|
||||||
|
<strong><link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}"></strong>
|
||||||
|
<strong><link rel="stylesheet" href="{{ url_for('static', filename='css/barchart.css') }}"></strong>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="logo">Fail*</h1>
|
||||||
|
<strong><nav>
|
||||||
|
<ul class="menu">
|
||||||
|
<li><a href="{{ url_for('index') }}">Home</a></li>
|
||||||
|
<li><a href="{{ url_for('about') }}">About</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav></strong>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<div id="footer">
|
||||||
|
© Fail* - Fault Injection Leveraged
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
39
tools/analysis/resultbrowser/app/views.py
Normal file
39
tools/analysis/resultbrowser/app/views.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
from flask import render_template,request
|
||||||
|
from app import app
|
||||||
|
|
||||||
|
import model
|
||||||
|
import data
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
@app.route('/index')
|
||||||
|
def index():
|
||||||
|
reload_overview = request.args.get('reload', False)
|
||||||
|
if reload_overview:
|
||||||
|
print "Reloading overview..."
|
||||||
|
model.reloadOverview()
|
||||||
|
return render_template("index.html", overview=model.getOverview(), objdump_there = model.objdumpExists())
|
||||||
|
|
||||||
|
@app.route('/code')
|
||||||
|
def code():
|
||||||
|
variant_id = request.args.get('variant_id', None)
|
||||||
|
resulttype = request.args.get('resulttype', None)
|
||||||
|
table = request.args.get('table', None)
|
||||||
|
res,restypes = model.getCode(table, variant_id, resulttype)
|
||||||
|
var_dets = model.getOverview().getVariantById(variant_id)
|
||||||
|
return render_template("code.html", results=res, resulttypes=restypes, variant_details=var_dets )
|
||||||
|
|
||||||
|
@app.route('/instr_details')
|
||||||
|
def instr_details():
|
||||||
|
table = request.args.get('table', None)
|
||||||
|
variant_id = request.args.get('variant_id', None)
|
||||||
|
instr_addr = request.args.get('instr_address', None)
|
||||||
|
resulttype = request.args.get('resulttype', None)
|
||||||
|
codeexcerpt = model.getCodeExcerpt(variant_id, instr_addr)
|
||||||
|
var_dets = model.getOverview().getVariantById(variant_id)
|
||||||
|
results = model.getResultsbyInstruction(table, variant_id, instr_addr, resulttype)
|
||||||
|
return render_template("instr_details.html", code=codeexcerpt, result=results, variant_details=var_dets)
|
||||||
|
|
||||||
|
@app.route('/about')
|
||||||
|
def about():
|
||||||
|
stat = model.showDBstatus()
|
||||||
|
return render_template("about.html", status=stat)
|
||||||
69
tools/analysis/resultbrowser/conf.yml
Normal file
69
tools/analysis/resultbrowser/conf.yml
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# YAML-based: http://yaml.org/
|
||||||
|
# Online parser for testing: http://yaml-online-parser.appspot.com/
|
||||||
|
# Some notes:
|
||||||
|
# YAML is case-sensitive and structured by indention!
|
||||||
|
#
|
||||||
|
# The 'defaults' section describes an *optional* default result type mapping for all tables.
|
||||||
|
# The 'tables' section describes result tables in more detail.
|
||||||
|
# A table consists of variants, each variant of benchmarks.
|
||||||
|
# Each of these configuration items
|
||||||
|
# title: Table title
|
||||||
|
# details: Some textual description
|
||||||
|
# mapping: A distinct mapping, if not set, the parent item's mapping is used
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
mapping:
|
||||||
|
Everything OK:
|
||||||
|
- OK
|
||||||
|
- OK_DETECTED_ERROR
|
||||||
|
- OK_WRONG_CONTROL_FLOW
|
||||||
|
Outside Data Section:
|
||||||
|
- ERR_OUTSIDE_DATA
|
||||||
|
Hardware Trap:
|
||||||
|
- ERR_OUTSIDE_TEXT
|
||||||
|
- ERR_TRAP
|
||||||
|
Silent Data Corruption:
|
||||||
|
- ERR_WRONG_RESULT
|
||||||
|
|
||||||
|
tables:
|
||||||
|
result_CoredVoterProtoMsg:
|
||||||
|
title: CoRed Voter Experiment Results
|
||||||
|
variants:
|
||||||
|
x86_cored_voter:
|
||||||
|
title: x86 CoRed Voter Experiment
|
||||||
|
details: Some interesting details about the experiment.
|
||||||
|
|
||||||
|
benchmarks:
|
||||||
|
ean-random-4:
|
||||||
|
title: Random 4 bit injections
|
||||||
|
details: |
|
||||||
|
The details can also written this way.
|
||||||
|
The pipe insert the newlines. Cool, isn't it?
|
||||||
|
|
||||||
|
ean-random-5:
|
||||||
|
title: Random 5 bit injections
|
||||||
|
details: Details about 5 bit random injection benchmark.
|
||||||
|
mapping:
|
||||||
|
Alright:
|
||||||
|
- OK
|
||||||
|
- OK_DETECTED_ERROR
|
||||||
|
- OK_WRONG_CONTROL_FLOW
|
||||||
|
Not Alright:
|
||||||
|
- ERR_OUTSIDE_DATA
|
||||||
|
- ERR_OUTSIDE_TEXT
|
||||||
|
- ERR_TRAP
|
||||||
|
- ERR_WRONG_RESULT
|
||||||
|
Timeout:
|
||||||
|
- ERR_TIMEOUT
|
||||||
|
# Another variant within result_CoredVoterProtoMsg
|
||||||
|
x86_cored_voter2:
|
||||||
|
title: variant title
|
||||||
|
details: variant details
|
||||||
|
benchmarks:
|
||||||
|
ean-random-2:
|
||||||
|
title: benchmarktitle
|
||||||
|
details: some benchmark details
|
||||||
|
|
||||||
|
ean-random-3:
|
||||||
|
title: benchmark random 3
|
||||||
|
details: some benchmark 3 details
|
||||||
5
tools/analysis/resultbrowser/run.py
Executable file
5
tools/analysis/resultbrowser/run.py
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
from app import app
|
||||||
|
from app import model
|
||||||
|
|
||||||
|
app.run(debug=False, port=int(model.opts.port), host=model.opts.host)
|
||||||
Reference in New Issue
Block a user