Source code for mcgdb.model.task.representation

"""
`Link`, `Endpoint` and `CommEntity` provide the generic basis for
building the debugger representation of task-based program structure.
"""

import gdb

import mcgdb
from mcgdb.toolbox import my_gdb


###########################################################"

@my_gdb.Listed
@my_gdb.Numbered


[docs]class Endpoint: """ Glue between an entity and a link. :param comm_entity: Entity to wich is endpoint is bound. :var link: Link to wich this endpoint if connected, if any. :var siblings: Endpoints identical to this one. """ def __init__(self, comm_entity): self.comm_entity = comm_entity if self not in self.comm_entity.endpoints: self.comm_entity.endpoints.append(self) self.link = None self.siblings = [] self.stop_next_requests = [] self.breakpoint_rq = None self.init() @my_gdb.virtual
[docs] def init(self): """ Initialization hook point for subclasses. """ pass
@my_gdb.internal
[docs] def comm_ent_exit(self): """ Notifies the endpoint that its entity exited. Informs the associated link, if any. """ if self.link is not None: self.link.endpoint_closed(self) self.comm_entity = None
[docs] def endpoint_closed(self): """ Closes the endpoint. Unbinds the link, and tells the entity. """ if self.link is not None: link = self.link self.link = None link.endpoint_closed(self) if self.comm_entity is not None: comm_ent = self.comm_entity self.comm_entity = None comm_ent.endpoint_closed(self)
[docs] def stop_next(self, message=None, permanent=False, cb=None): """ Requests an execution stop next time a message is carried over this endpoint. All the parameters are optional. :param message: Message to display when the execution is stopped. :type message: String. :param permanent: False if the request should be destroyed after the first stop, True otherwise. Default: False. :type permanent: Boolean :param cb: Function callback applied to the stop reason, that returns a stop message. :type cb: <string> Callable(<string>) :returns: StopRequest(arg, permanent, cb) :rtype: StopRequest. """ rq = StopRequest(arg, permanent, cb) self.stop_next_requests.append(rq) return rq
@my_gdb.internal
[docs] def get_stop_next(self, reason=None): """ Tells if this endpoint wants the execution to be stopped. :returns: #1 True if the execution should stop, False otherwise. :returns: #2 List of stop messages. :rtype: (#1:Boolean, #2List) """ requests = self.stop_next_requests self.stop_next_requests = [] stop_msgs = [] do_stop = False for rq in requests: do_stop = True if rq.cb is not None: stop_msgs.append(rq.cb(reason)) if rq.message is not None: stop_msgs.append(rq.string) if rq.permanent: self.stop_next_requests.append(rq) return do_stop, stop_msgs
@my_gdb.internal
[docs] def undo_request(self, rq): """ Cancels a stop request. :param rq: a stop request generated by `self.stop_next` :type rq: StopRequest """ return self.stop_next_requests.remove(rq)
@my_gdb.Listed @my_gdb.Switchable @my_gdb.Numbered
[docs]class CommEntity: """ Class representing a model entity that can communicate and build networks through Endpoints and Links. """ TASK_MANAGER = None def __init__(self): self.task = None if self.__class__.TASK_MANAGER is None: self.task = my_gdb.get_selected_task() self.endpoints = [] self.init() @my_gdb.virtual
[docs] def init(self): """ Initialization hook point for subclasses. """ pass
[docs] def add_endpoint(self, endpoint): """ Adds an endpoint to this entity. :param endpoint: the new endpoint. :type endpoint: Endpoint """ self.endpoints.append(endpoint) endpoint.comm_entity = self
[docs] def endpoint_closed(self, endpoint): """ Notifies the entity that `endpoint` was closed. :param endpoint: the endpoint that was closed. :type endpoint: Endpoint """ assert endpoint is not None endpoint.comm_entity = None try: self.endpoints.remove(endpoint) except ValueError: pass self.check_useless()
@my_gdb.virtual
[docs] def check_useless(self): """ Hook point to tell if we can get rid of this entity. """ return False
@my_gdb.virtual def __str__(self): return "CommEntity[X]" @my_gdb.virtual
[docs] def is_alive(self): """ Hook point for implementation specific life checking. """ return True
@my_gdb.virtual
[docs] def do_exit(self): """ Hook point to release internal resources. """ pass
@my_gdb.internal
[docs] def exit(self): """ Tells the entity to quit. """ self.do_exit()
@my_gdb.virtual
[docs] def assert_self_consistency(self): """ Hook point to assert that the entity is in a consistent state, or raise exceptions otherwise. """ pass
@my_gdb.internal
[docs] def get_mark(self): """ :returns: the task mark from the task manager if any, or an empty string. :rtype: String """ if self.__class__.TASK_MANAGER is None: return "" return self.__class__.TASK_MANAGER.get_mark(self.task)
@my_gdb.internal
[docs] def switch(self, force=False): """ Switches to this entity. :param force: Should the task manager force the switch or not. :returns: `None` if there is no inferior associated with this task, :returns: `False` if it was not possible to switch, :returns: `True` if GDB has switched to the entity. """ self.assert_self_consistency() if self.task is None: return None else: my_gdb.log.info("[Switching to %s]", self) return self.__class__.TASK_MANAGER.switch_to(self.task, force)
@my_gdb.virtual
[docs] def get_messages(self): return None
@classmethod
[docs] def get_current(cls): """ :returns: the entity currently active, if any. """ for ent in cls.dict_.values(): if ent.is_current(): return ent
@classmethod
[docs] def get_selected_component(cls, silent=False): if cls.get_selected_component.im_func is not CommEntity.get_selected_component.im_func: return cls.get_selected_component(silent) else: if not silent: my_gdb.log.warning("No CommComponent.get_selected_component implemented...")
@my_gdb.Numbered
[docs]class Message: """ Object transmitted between entities, over communication endpoints and links. :param id: identifier of the message's creation point :param payload: the content of the message. :param name: the name of the message. :var breakpoint: True if the execution should be stopped when this message is processed. :var breakpoint_cnt: Breakpoint counter, incremented each time this message stops the execution. :var checkpoints: list of (id, payload) checkpoint crossed by this message. """ def __init__(self, id_, payload=None, name=None): self.name = name self.checkpoints = [(id_, payload)] self.breakpoint = False self.breakpoint_cnt = 0
[docs] def checkpoint(self, id_, payload=None): """ Adds a new checkpoint on the way of the message. :param id: identifier of this checkpoint :param payload: content of the message at this checkpoint. If the `payload` is `None`, we reuse the previous one. """ if payload is None: last_id, payload = self.last_checkpoint() self.checkpoints.append((id_, payload))
[docs] def last_checkpoint(self): """ :returns: the last checkpoint crossed by this message. :rtype: (id, payload) """ return self.checkpoints[-1]
[docs] def last_payload(self): """ :returns: the payload of the last checkpoint crossed by this message. """ return self.checkpoints[-1][1]
def __str__(self): return "Message[%s]" % self.name
[docs] def check_breakpoint(self, src, dst): """ Requests an execution stop to GDB if this message is breakpointed. :param src: Source of the message's last hope. :param dst: Destination of the message's last hope. """ if self.breakpoint: self.breakpoint_cnt += 1 my_gdb.push_stop_request( "[Message breakpoint for '%s': %s --> %s]" % (self, src, dst))
@staticmethod @my_gdb.generator
[docs] def all_messages(): """ Generator. Get all the messages stored in the entities and links. :returns: Iterator yielding all the available messages. """ for ent in CommEntity.list_: for msg in ent.get_messages(): yield msg for link in Link.list_: for msg in link.get_messages(): yield msg
@my_gdb.Listed @my_gdb.Numbered @my_gdb.Dicted
[docs]class CommComponent(CommEntity): """ Extention of generic communication entities. Represents a generic component. """ def __init__(self): CommEntity.__init__(self) @classmethod
[docs] def get_selected_component(cls, silent=False): """ :returns: the component currently active, or None. :rtype: CommComponent """ for comp in CommComponent.list_: if comp.get_mark() == "*": return comp