import gdb
import mcgdb.interaction
from .python_utils import *
import traceback
import logging;
log = logging.getLogger(__name__)
log_user = logging.getLogger("mcgdb.log.user")
###################
[docs]class Catchable:
catch = {}
ALL_ENTITIES = object()
@staticmethod
[docs] def register(name):
Catchable.catch[name] = []
@staticmethod
[docs] def values():
return Catchable.catch.items()
@staticmethod
[docs] def keys():
return Catchable.catch.keys()
@staticmethod
[docs] def addRemove(name, entity, do_add):
if do_add:
Catchable.catchable_add(name, entity)
else:
Catchable.catchable_remove(name, entity)
@staticmethod
[docs] def activate(name, entity):
lst = Catchable.catch[name]
if entity is None:
entity = ALL_ENTITIES
while len(lst) != 0:
lst.pop()
lst.append(entity)
@staticmethod
[docs] def remove(name, entity):
lst = catch[name]
if entity is None:
while len(lst) != 0:
lst.pop()
else:
Catchable.catch[name].remove(entity)
@staticmethod
[docs] def is_set(name, entity=None):
return (ALL_ENTITIES in Catchable.catch[name]
or entity in Catchable.catch[name])
catchable = Catchable()
################################################
models = {}
def register_model(name, key, toggle_activate, objfile=False, binname=False):
"""
Registers a new model in mcGDB.
:param name: name of the model
:param key: name of a function that should be looked for to decide
to activate the model.
:param toggle_activate: called once with param `do_activate=True`
when mcGDB wants to active the model; called once with
`do_activate=False` when mcGDB wants to desactive the model.
:type toggle_activate: Callable(do_activate=<Boolean>)
"""
models[key] = SimpleClass({"name": name, "key": key,
"toggle_activate": toggle_activate,
"is_enabled": False, "is_failed": False,
"by_binname": binname,
"objfile": objfile})
@internal
def inferior_has_model(key, objfile=None):
"""
:returns: True if symbol `key` if defined in GDB's inferior.
"""
if objfile:
return objfile.filename.find(key) != -1
elif gdb.lookup_global_symbol(key) is not None:
return True
try:
gdb.parse_and_eval(key)
return True
except gdb.error:
pass
return False
def callback_crash(location=None, ex=""):
if False:
return
if location is None:
location = 'not provided'
log_user.warning("Callback for '{}' failed ({})".format(location, ex))
log_user.warning("Starting post mortem debugger...")
type, value, tb = sys.exc_info()
traceback.print_exc()
import pdb; pdb.post_mortem(tb)
@internal
def check_new_objfile_for_models(evt):
log_event = logging.getLogger("mcgdb.log.event.new_objfile")
log_event.info("checking models on {}".format(evt.new_objfile.filename))
detect_models(evt.new_objfile)
@internal
def enable_model(model):
if model.is_enabled or model.is_failed:
return
log_user.info("Enable model {}".format(model.name))
try:
model.toggle_activate(do_activate=True, include_self=True)
model.is_enabled = True
except Exception as e:
log.error("Could not active model {}.".format(model.name))
log.warning(e)
log.warning(traceback.format_exc())
model.is_failed = True
@internal
def load_models_by_name(binname):
lst = list(models.items())
for key, model in lst:
if not model.by_binname:
continue
if model.key in binname:
enable_model(model)
# if new models were inserted
if len(lst) != len(list(models.items())):
load_models_by_name(binname)
@internal
def detect_models(new_objfile=None):
"""
Goes through all the registed models and activate the relevant one(s).
"""
copy = dict(models.items())
for key, model in copy.items():
if not inferior_has_model(key, new_objfile):
continue
enable_model(model)
@internal
def toggle_activate_submodules(name):
def do_toggle(do_activate, include_self=False):
mod_list = inspect.getmembers(sys.modules[name])
if include_self:
mod_list = itertools.chain([(name, sys.modules[name])], mod_list)
for mod_name, mod in mod_list:
if not inspect.ismodule(mod): continue
if do_activate and hasattr(mod, "activate"):
if hasattr(mod, "activated") and getattr(mod, "activated"):
continue
try:
getattr(mod, "activate")()
setattr(mod, "activated", True)
except Exception as e:
log.error("Activation of module {} ({}) failed: {}".format(name, mod_name, e))
log.warn(e)
if not do_activate and hasattr(mod, "deactivate"):
if hasattr(mod, "deactivated") and getattr(mod, "deactivated"):
continue
try:
getattr(mod, "deactivate")()
setattr(mod, "deactivated", True)
except Exception as e:
log.error("Deactivation of module {} ({}) failed: {}".format(name, mod_name, e))
log.warn(e)
return do_toggle
class BugFixFrame(gdb.frames.FrameDecorator):
def function(self):
return self.inferior_frame().name()
class BugFixFrameFilter:
def __init__(self):
self.enabled = True
self.priority = 99999
def filter(self, frames):
for frame in frames:
yield BugFixFrame(frame)
log.info("FrameDecorator bug fixer frame filter registered.")
gdb.frame_filters["Bug fix frame filter"] = BugFixFrameFilter()