예제 #1
0
class DotGraph:
    def __init__(self, functions):
        self.node_dic = {}
        self.edge_dic = {}
        self.graph = Dot()
        self.html = None

        for f in functions:
            if f.name in [
                    'slitherConstructorVariables',
                    'slitherConstructorConstantVariables'
            ]:
                continue
            self.construct_node(f)

        self.construct_graph(functions)
        self.html = svg_to_html(self.graph.create_svg().decode('utf-8'))

    def construct_node(self, function):
        n = Node(function.name)
        n.set_tooltip(construct_tooltip(function))
        self.node_dic[function.name] = n
        self.graph.add_node(n)

    def construct_graph(self, functions):
        for f in functions:
            if (f.name in [
                    'slitherConstructorVariables',
                    'slitherConstructorConstantVariables'
            ] or f.slither_function.is_constructor):
                continue

            for sr in f.read:
                for written_f in sr.written_by:
                    if written_f.name not in [
                            'slitherConstructorVariables',
                            'slitherConstructorConstantVariables'
                    ]:
                        n1 = self.get_node(f.name)
                        n2 = self.get_node(written_f.name)
                        if self.edge_dic.get((n1, n2)):
                            e = self.edge_dic[(n1, n2)]
                            old_label = e.get_label()
                            e.set_label(
                                f'{old_label.strip()}, {sr.name}        ')
                        else:
                            self.construct_edge(n1, n2)
                            e = self.edge_dic[(n1, n2)]
                            e.set_label(f'{sr.name}        ')

    def construct_edge(self, _n1: Node, _n2: Node):
        e = Edge(_n1, _n2, fontsize="8", fontcolor="#2E86C1", arrowsize="0.7")
        self.edge_dic[(_n1, _n2)] = e
        self.graph.add_edge(e)

    def get_node(self, _name):
        return self.node_dic.get(_name)
class DependencyGraph:
    def __init__(self, _contract: Contract):
        """
        Takes a Contract object and constructs the DDG for it.

        *** To be completed
            Currently cannot detect indirect read.
            Indirect write can be detected.
        """
        self.contract = _contract
        self.node_dic = {}
        self.edge_dic = {}
        self.graph = Dot()

        for f in _contract.functions + _contract.constructor_as_list:
            if f.name in ['slitherConstructorVariables', 'slitherConstructorConstantVariables'] or not f.is_public_or_external:
                continue
            self.construct_node(f)

        self.construct_graph(_contract)

    @property
    def html(self):
        return svg_to_html(self.graph.create_svg().decode('utf-8'))

    def construct_graph(self, _contract):
        """
        Constructs the graph by connecting nodes with edges.
        """
        for f in _contract.functions + _contract.constructor_as_list:
            if f.name in ['slitherConstructorVariables', 'slitherConstructorConstantVariables'] or not f.is_public_or_external:
                continue

            for dependency in f.depends_on:
                written_f, sr = dependency[0], dependency[1]
                n1 = self.get_node(f.name)
                n2 = self.get_node(written_f.name)
                if self.edge_dic.get((n1, n2)):
                    e = self.edge_dic[(n1, n2)]
                    old_label = e.get_label()
                    e.set_label(f'{old_label.strip()}, {sr.name}        ')
                else:
                    self.construct_edge(n1, n2)
                    e = self.edge_dic[(n1, n2)]
                    e.set_label(f'{sr.name}        ')

    def update_graph(self):
        remaining_edges_dic = defaultdict(list)
        for f in self.contract.functions + self.contract.constructor_as_list:
            if f.name in ['slitherConstructorVariables', 'slitherConstructorConstantVariables'] or not f.is_public_or_external:
                continue

            for dependency in f.depends_on:
                written_f, sr = dependency[0], dependency[1]
                n1 = self.get_node(f.name)
                n2 = self.get_node(written_f.name)
                remaining_edges_dic[(n1, n2)].append(sr)

        existing_edges = self.edge_dic.keys()
        remaining_edges = remaining_edges_dic.keys()

        for ex_edge in existing_edges:
            if ex_edge not in remaining_edges:
                remove_edge(self.edge_dic[ex_edge])
            # no need to check if only one state variable dependency is remove
            # because if a dependency between two functions is removed
            # all of its dependency based on whatever variable will be removed.

    def construct_node(self, _function: Function):
        """
        Takes a Function object and constructs a Dot Node object for it.
        Adds the created object to the dictionary.

        Finished.
        """
        n = Node(_function.name)
        n.set_tooltip(construct_tooltip(_function))
        self.node_dic[_function.name] = n
        self.graph.add_node(n)

    def get_node(self, _name):
        return self.node_dic.get(_name)

    def construct_edge(self, _n1: Node, _n2: Node):
        """
        Takes two nodes
        n1 depends on n2
        n1 points to n2
        Constructs the edge object and adds it to the dictionary.

        Finished.
        """
        e = Edge(_n1, _n2, fontsize="8", fontcolor="#2E86C1", arrowsize="0.7")
        self.edge_dic[(_n1, _n2)] = e
        # e.set('color', 'green')
        self.graph.add_edge(e)
예제 #3
0
class SysCDiagramPlugin():

    def initPlugin(self, signalproxy):
        """Initialise the systemc block diagram plugin"""

        self.signalproxy = signalproxy
        self.do = signalproxy.distributedObjects

        # systemc stuff and and pointer type strings needed for casting in gdb
        # because systemc objects can be systemc modules, systemc ports, etc.
        self.ctx = None
        self.ctx_pointer = None
        self.ctx_func = "sc_get_curr_simcontext()"
        self.ctx_found = False

        self.ctx_type = "(sc_core::sc_simcontext*)"
        self.port_type = "(sc_core::sc_port_base*)"
        self.module_type = "(sc_core::sc_module*)"
        self.object_type = "(sc_core::sc_object*)"
        self.prim_channel_type = "(sc_core::sc_prim_channel*)"

        # dict with a string that represents the pointer as key and
        # a nested dict with parent, children, etc as key-values
        #   dst_dict[ptr] = {"wrapper":    vw,
        #                    "name":       None,
        #                    "parent_ptr": None,
        #                    "children":   {}}
        self.sysc_modules = {}
        self.sysc_objects = {}
        self.sysc_ports = {}
        self.sysc_prim_channels = {}

        # because of how we built the interface for the tracepoints on the
        # datagraph we first need to create an file obj. We choose StringIO
        # because it uses a string as buffer and does not acces the filesystem
        self._file_obj = StringIO()
        self.image = SVGImage("SystemC Block Diagram", self._file_obj)
        self.image_wrapper = SVGDataGraphVW(self.image, self.do)

        self.signalproxy.inferiorStoppedNormally.connect(self.update)

        # hook Datagraph variable wrapper into the datagraph controller
        # after self.action.commit is called the image will be displayed at the
        # datagraph
        self.action = self.do.actions.\
            getAddSVGToDatagraphAction(self.image_wrapper,
                                       self.do.
                                       datagraphController.addVar)

        # pydot graph visualization library
        self.block_diagram = Dot(graph_type='digraph')
        self.block_diagram.set_graph_defaults(compound='true',
                                              splines='ortho',
                                              rankdir='LR')
        self.block_diagram.set_node_defaults(shape='box')

        # Needed for creating the right variables and variable wrappers from
        # the systemc pointers
        self.vwFactory = VarWrapperFactory()
        self.variableList = VariableList(self.vwFactory, self.do)

    def deInitPlugin(self):
        pass

    def evaluateExp(self, exp):
        return self.signalproxy.gdbEvaluateExpression(exp)

    def showDiagram(self):
        self.action.commit()

    def update(self):
        if not self.ctx_found and self.ctx is None:
            self.__findSimContext()
            if self.ctx is None:
                return
        else:
            # don't try to analyze if elaboration is not done
            if not cpp2py(self.ctx["m_elaboration_done"].value):
                return

        # prepare for easy information collection
        object_vec = self.ctx["m_child_objects"]

        # find all relevant information
        self.__findSysCObjects(object_vec, self.object_type, self.sysc_objects)

        # if there are no objects to draw than skip the drawing part
        # this might happen if you set the breakpoint before any objects are
        # created. This is actually catched above, but there might also be a
        # design with no objects.
        if len(self.sysc_objects.keys()) == 0:
            return

        clusters = {}
        nodes = {}

        # build pydot hierachy and add all subgraphs and nodes to the main
        # graph
        self.__buildHierachy(self.sysc_objects, clusters, nodes)
        for sptr in clusters:
            self.block_diagram.add_subgraph(clusters[sptr])
        for sptr in nodes:
            self.block_diagram.add_node(nodes[sptr])

        self._file_obj.write(self.block_diagram.create_svg())
        self.signalproxy.inferiorStoppedNormally.disconnect(self.update)
        self.showDiagram()

    def __buildHierachy(self, obj_dict, clusters, nodes):
        """ Build Cluster and Node hierachy for pydot
        """
        for ptr in obj_dict:
            obj = obj_dict[ptr]
            if ptr in (self.sysc_ports.keys()+self.sysc_prim_channels.keys()):
                continue

            if len(obj["children"].keys()) == 0:
                node = Node(obj["name"])
                nodes[ptr] = node
            else:
                clust = Cluster(obj["name"].replace(".", "_"),
                                color='red',
                                label=obj["name"])
                c_clusters = {}
                c_nodes = {}
                self.__buildHierachy(obj["children"], c_clusters, c_nodes)
                for sptr in c_clusters:
                    clust.add_subgraph(c_clusters[sptr])
                for sptr in c_nodes:
                    clust.add_node(c_nodes[sptr])
                clusters[ptr] = clust

    def __findSysCObjects(self, obj_vec, obj_type, dst_dict):
        """ Find sc_object from module, port and prim channel registry
        """
        for i in obj_vec.childs:
            ptr = i.value
            var = "(*{}{})".format(obj_type, ptr)
            vw = self.variableList.addVarByName(var)
            dst_dict[ptr] = {"wrapper":    vw,
                             "name":       None,
                             "parent_ptr": None,
                             "children":   {}}

            for member in vw.childs:
                if member.exp == "m_name":
                    dst_dict[ptr]["name"] = member.value.strip('"')

                elif member.exp == "m_child_objects":
                    children = {}
                    self.__findSysCObjects(vw["m_child_objects"],
                                           obj_type,
                                           children)
                    dst_dict[ptr]["children"] = children

                elif member.exp == "m_parent":
                    dst_dict[ptr]["parent_ptr"] = member.value

    def __findSimContext(self):
        """ Find systemc simulation context
        """
        self.ctx_pointer = self.evaluateExp(self.ctx_func)
        if self.ctx is None:
            frame = 0
            depth = self.signalproxy.gdbGetStackDepth()
            while (self.ctx_pointer is None) and frame <= depth:
                frame += 1
                self.signalproxy.gdbSelectStackFrame(frame)
                self.ctx_pointer = self.evaluateExp(self.ctx_func)
            else:
                if self.ctx_pointer is None:
                    self.ctx_found = False
                    return
                else:
                    self.ctx_found = True
                    self.ctx = self.do.variablePool.getVar(self.ctx_func)["*"]
        else:
            self.ctx_found = True
            self.ctx = self.do.variablePool.getVar(self.ctx_func)["*"]