mirror of
https://github.com/gaasedelen/lighthouse
synced 2026-06-08 14:19:10 +00:00
147 lines
5.9 KiB
Python
147 lines
5.9 KiB
Python
from lighthouse.util.log import lmsg
|
|
from lighthouse.util.misc import iteritems
|
|
from lighthouse.util.disassembler import disassembler
|
|
|
|
#------------------------------------------------------------------------------
|
|
# Exception Definitions
|
|
#------------------------------------------------------------------------------
|
|
|
|
class LighthouseError(Exception):
|
|
"""
|
|
An error generated by Lighthouse.
|
|
"""
|
|
def __init__(self, *args, **kwargs):
|
|
super(LighthouseError, self).__init__(*args, **kwargs)
|
|
|
|
#------------------------------------------------------------------------------
|
|
# Coverage File Exceptions
|
|
#------------------------------------------------------------------------------
|
|
|
|
class CoverageException(LighthouseError):
|
|
"""
|
|
A class of errors pertaining to loading & mapping coverage files.
|
|
"""
|
|
name = NotImplementedError
|
|
description = NotImplementedError
|
|
|
|
def __init__(self, message, filepath):
|
|
super(CoverageException, self).__init__(message)
|
|
self.filepath = filepath
|
|
|
|
@property
|
|
def verbose(self):
|
|
return "Error: %s\n\n%s" % (self.name, self.description)
|
|
|
|
def __str__(self):
|
|
return self.message + " '%s'" % self.filepath
|
|
|
|
class CoverageParsingError(CoverageException):
|
|
"""
|
|
An error generated by the CoverageReader when all parsers fail.
|
|
"""
|
|
name = "PARSE_FAILURE"
|
|
description = \
|
|
"Failed to parse one or more of the selected coverage files!\n\n" \
|
|
" Possible reasons:\n" \
|
|
" - You selected a file that was *not* a coverage file.\n" \
|
|
" - The selected coverage file is malformed or unreadable.\n" \
|
|
" - A suitable parser for the coverage file is not installed.\n\n" \
|
|
"Please see the disassembler console for more info..."
|
|
|
|
def __init__(self, filepath, tracebacks):
|
|
super(CoverageParsingError, self).__init__("Failed to parse coverage file", filepath)
|
|
self.tracebacks = tracebacks
|
|
|
|
class CoverageMissingError(CoverageException):
|
|
"""
|
|
An error generated when no data was extracted from a CoverageFile.
|
|
"""
|
|
name = "NO_COVERAGE_ERROR"
|
|
description = \
|
|
"No usable coverage data was extracted from one of the selected files.\n\n" \
|
|
" Possible reasons:\n" \
|
|
" - You selected a coverage file for the wrong binary.\n" \
|
|
" - The name of the executable file used to generate this database\n" \
|
|
" is different than the one you collected coverage against.\n" \
|
|
" - Your DBI failed to collect any coverage for this binary.\n\n" \
|
|
"Please see the disassembler console for more info..."
|
|
|
|
def __init__(self, filepath):
|
|
super(CoverageMissingError, self).__init__("No coverage extracted from file", filepath)
|
|
|
|
class CoverageMappingAbsent(CoverageException):
|
|
"""
|
|
A warning generated when coverage data cannot be mapped.
|
|
"""
|
|
name = "NO_COVERAGE_MAPPED"
|
|
description = \
|
|
"One or more of the loaded coverage files has no visibly mapped data.\n\n" \
|
|
" Possible reasons:\n" \
|
|
" - The loaded coverage data does not fall within defined functions.\n" \
|
|
" - You loaded an absolute address trace with a different imagebase.\n" \
|
|
" - The coverage data might be corrupt or malformed.\n\n" \
|
|
"Please see the disassembler console for more info..."
|
|
|
|
def __init__(self, coverage):
|
|
super(CoverageMappingAbsent, self).__init__("No coverage data could be mapped", coverage.filepath)
|
|
self.coverage = coverage
|
|
|
|
class CoverageMappingSuspicious(CoverageException):
|
|
"""
|
|
A warning generated when coverage data does not appear to match the database.
|
|
"""
|
|
name = "BAD_COVERAGE_MAPPING"
|
|
description = \
|
|
"One or more of the loaded coverage files appears to be badly mapped.\n\n" \
|
|
" Possible reasons:\n" \
|
|
" - You selected the wrong binary/module to load coverage from.\n" \
|
|
" - Your coverage file/data is for a different version of the\n" \
|
|
" binary that does not match what the disassembler has open.\n" \
|
|
" - You recorded self-modifying code or something with very\n" \
|
|
" abnormal control flow (obfuscated code, malware, packers).\n" \
|
|
" - The coverage data might be corrupt or malformed.\n\n" \
|
|
"This means that any coverage displayed by Lighthouse is PROBABLY\n" \
|
|
"WRONG and is not be trusted because the coverage data does not\n" \
|
|
"appear to match the disassembled binary."
|
|
|
|
def __init__(self, coverage):
|
|
super(CoverageMappingSuspicious, self).__init__("Coverage data appears badly mapped", coverage.filepath)
|
|
self.coverage = coverage
|
|
|
|
#------------------------------------------------------------------------------
|
|
# UI Warnings
|
|
#------------------------------------------------------------------------------
|
|
|
|
def warn_errors(errors, ignore=[]):
|
|
"""
|
|
Warn the user of any encountered errors with a messagebox.
|
|
"""
|
|
if not errors:
|
|
return
|
|
|
|
for error_type, error_list in iteritems(errors):
|
|
|
|
#
|
|
# loop through the individual instances/files that caused this error
|
|
# and dump the results to the disassembler console...
|
|
#
|
|
|
|
lmsg("-"*50)
|
|
lmsg("Files reporting %s:" % error_type.name)
|
|
for error in error_list:
|
|
lmsg(" - %s" % error.filepath)
|
|
|
|
# suppress popups for certain errors, if the user has specified such
|
|
if error_type in ignore:
|
|
continue
|
|
|
|
#
|
|
# popup a more verbose error messagebox for the user to read regarding
|
|
# this class of error they encountered
|
|
#
|
|
|
|
disassembler.warning(error.verbose)
|
|
|
|
# done ...
|
|
lmsg("-"*50)
|