cz.afri.smg.graphs.SMGObjectNode.java Source code

Java tutorial

Introduction

Here is the source code for cz.afri.smg.graphs.SMGObjectNode.java

Source

/*
 *  This file is part of SMG, a symbolic memory graph Java library
 *  Originally developed as part of CPAChecker, the configurable software verification platform
 *
 *  Copyright (C) 2011-2015  Petr Muller
 *  Copyright (C) 2007-2014  Dirk Beyer
 *  All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
package cz.afri.smg.graphs;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import com.google.common.base.Joiner;
import com.google.common.base.Strings;

import cz.afri.smg.graphs.SMGValues.SMGExplicitValue;
import cz.afri.smg.graphs.SMGValues.SMGKnownSymValue;
import cz.afri.smg.objects.SMGObject;
import cz.afri.smg.objects.SMGObjectVisitor;
import cz.afri.smg.objects.SMGRegion;
import cz.afri.smg.objects.sll.SMGSingleLinkedList;
import cz.afri.smg.objects.tree.SimpleBinaryTree;

final class SMGObjectNode {
    private final String name;
    private final String definition;
    private static int counter = 0;

    public SMGObjectNode(final String pType, final String pDefinition) {
        name = "node_" + pType + "_" + counter++;
        definition = pDefinition;
    }

    public SMGObjectNode(final String pName) {
        name = pName;
        definition = null;
    }

    public String getName() {
        return name;
    }

    public String getDefinition() {
        return name + "[" + definition + "];";
    }
}

class SMGNodeDotVisitor extends SMGObjectVisitor {
    private final ReadableSMG smg;
    private SMGObjectNode node = null;

    public SMGNodeDotVisitor(final ReadableSMG pSmg) {
        smg = pSmg;
    }

    private String defaultDefinition(final String pColor, final String pShape, final String pStyle,
            final SMGObject pObject) {
        return "color=" + pColor + ", shape=" + pShape + ", style=" + pStyle + ", label =\"" + pObject.toString()
                + "\"";
    }

    @Override
    public void visit(final SMGRegion pRegion) {
        String shape = "rectangle";
        String color;
        String style;
        if (smg.isObjectValid(pRegion)) {
            color = "black";
            style = "solid";
        } else {
            color = "red";
            style = "dotted";
        }

        node = new SMGObjectNode("region", defaultDefinition(color, shape, style, pRegion));
    }

    @Override
    public void visit(final SMGSingleLinkedList pSll) {
        String shape = "rectangle";
        String color = "blue";

        String style = "dashed";
        node = new SMGObjectNode("sll", defaultDefinition(color, shape, style, pSll));
    }

    @Override
    public void visit(final SimpleBinaryTree pTree) {
        String shape = "rectangle";
        String color = "green";

        String style = "dashed";
        node = new SMGObjectNode("tree", defaultDefinition(color, shape, style, pTree));
    }

    @Override
    public void visit(final SMGObject pObject) {
        if (pObject.notNull()) {
            pObject.accept(this);
        } else {
            node = new SMGObjectNode("NULL");
        }
    }

    public SMGObjectNode getNode() {
        return node;
    }
}

public final class SMGPlotter {
    public static void debuggingPlot(final ReadableSMG pSmg, final String pId) throws IOException {
        SMGPlotter plotter = new SMGPlotter();
        PrintWriter writer = new PrintWriter(pId + ".dot", "UTF-8");
        writer.write(plotter.smgAsDot(pSmg, pId, pId));
        writer.close();
    }

    private final HashMap<SMGObject, SMGObjectNode> objectIndex = new HashMap<>();
    private static int nulls = 0;
    private int offset = 0;

    public SMGPlotter() {
    } /* utility class */

    public static String convertToValidDot(final String original) {
        return original.replaceAll("[:]", "_");
    }

    public String smgAsDot(final ReadableSMG smg, final String name, final String location) {
        StringBuilder sb = new StringBuilder();

        sb.append("digraph gr_" + name.replace('-', '_') + "{\n");
        offset += 2;
        sb.append(newLineWithOffset("label = \"Location: " + location.replace("\"", "\\\"") + "\";"));

        addStackSubgraph(smg, sb);

        SMGNodeDotVisitor visitor = new SMGNodeDotVisitor(smg);

        for (SMGObject heapObject : smg.getHeapObjects()) {
            if (!objectIndex.containsKey(heapObject)) {
                visitor.visit(heapObject);
                objectIndex.put(heapObject, visitor.getNode());
            }
            if (heapObject.notNull()) {
                sb.append(newLineWithOffset(objectIndex.get(heapObject).getDefinition()));
            }
        }

        addGlobalObjectSubgraph(smg, sb);

        for (Integer value : smg.getValues()) {
            if (value != smg.getNullValue()) {
                SMGExplicitValue explicitValue = smg.getExplicit(SMGKnownSymValue.valueOf(value));
                String explicitValueString;
                if (explicitValue.isUnknown()) {
                    explicitValueString = "";
                } else {
                    explicitValueString = " : " + String.valueOf(explicitValue.getAsLong());
                }
                sb.append(newLineWithOffset(smgValueAsDot(value, explicitValueString)));
            }
        }

        for (SMGEdgeHasValue edge : smg.getHVEdges()) {
            sb.append(newLineWithOffset(smgHVEdgeAsDot(edge)));
        }

        for (SMGEdgePointsTo edge : smg.getPTEdges()) {
            if (edge.getValue() != smg.getNullValue()) {
                sb.append(newLineWithOffset(smgPTEdgeAsDot(edge)));
            }
        }

        sb.append("}");

        return sb.toString();
    }

    private void addStackSubgraph(final ReadableSMG pSmg, final StringBuilder pSb) {
        pSb.append(newLineWithOffset("subgraph cluster_stack {"));
        offset += 2;
        pSb.append(newLineWithOffset("label=\"Stack\";"));

        int i = pSmg.getStackFrames().size();
        for (CLangStackFrame stackItem : pSmg.getStackFrames()) {
            addStackItemSubgraph(stackItem, pSb, i);
            i--;
        }
        offset -= 2;
        pSb.append(newLineWithOffset("}"));
    }

    private void addStackItemSubgraph(final CLangStackFrame pStackFrame, final StringBuilder pSb,
            final int pIndex) {
        pSb.append(newLineWithOffset(
                "subgraph cluster_stack_" + pStackFrame.getFunctionDeclaration().getName() + "{"));
        offset += 2;
        pSb.append(newLineWithOffset("fontcolor=blue;"));
        pSb.append(newLineWithOffset(
                "label=\"#" + pIndex + ": " + pStackFrame.getFunctionDeclaration().toString() + "\";"));

        HashMap<String, SMGRegion> toPrint = new HashMap<>();
        toPrint.putAll(pStackFrame.getVariables());

        SMGRegion returnObject = pStackFrame.getReturnObject();
        if (returnObject != null) {
            toPrint.put(CLangStackFrame.RETVAL_LABEL, returnObject);
        }

        pSb.append(newLineWithOffset(smgScopeFrameAsDot(toPrint, String.valueOf(pIndex))));

        offset -= 2;
        pSb.append(newLineWithOffset("}"));

    }

    private String smgScopeFrameAsDot(final Map<String, SMGRegion> pNamespace, final String pStructId) {
        StringBuilder sb = new StringBuilder();
        sb.append("struct" + pStructId + "[shape=record,label=\" ");

        // I sooo wish for Python list comprehension here...
        ArrayList<String> nodes = new ArrayList<>();
        for (Entry<String, SMGRegion> entry : pNamespace.entrySet()) {
            String key = entry.getKey();
            SMGObject obj = entry.getValue();

            if (key.equals("node")) {
                // escape Node1
                key = "node1";
            }

            nodes.add("<item_" + key + "> " + obj.toString());
            objectIndex.put(obj, new SMGObjectNode("struct" + pStructId + ":item_" + key));
        }
        sb.append(Joiner.on(" | ").join(nodes));
        sb.append("\"];\n");
        return sb.toString();
    }

    private void addGlobalObjectSubgraph(final ReadableSMG pSmg, final StringBuilder pSb) {
        if (pSmg.getGlobalObjects().size() > 0) {
            pSb.append(newLineWithOffset("subgraph cluster_global{"));
            offset += 2;
            pSb.append(newLineWithOffset("label=\"Global objects\";"));
            pSb.append(newLineWithOffset(smgScopeFrameAsDot(pSmg.getGlobalObjects(), "global")));
            offset -= 2;
            pSb.append(newLineWithOffset("}"));
        }
    }

    private static String newNullLabel() {
        SMGPlotter.nulls += 1;
        return "value_null_" + SMGPlotter.nulls;
    }

    private String smgHVEdgeAsDot(final SMGEdgeHasValue pEdge) {
        if (pEdge.getValue() == 0) {
            String newNull = newNullLabel();
            return newNull + "[shape=plaintext, label=\"NULL\"];" + objectIndex.get(pEdge.getObject()).getName()
                    + " -> " + newNull + "[label=\"[" + pEdge.getOffset() + "]\"];";
        } else {
            return objectIndex.get(pEdge.getObject()).getName() + " -> value_" + pEdge.getValue() + "[label=\"["
                    + pEdge.getOffset() + "]\"];";
        }
    }

    private String smgPTEdgeAsDot(final SMGEdgePointsTo pEdge) {
        return "value_" + pEdge.getValue() + " -> " + objectIndex.get(pEdge.getObject()).getName() + "[label=\"+"
                + pEdge.getOffset() + "b\"];";
    }

    private static String smgValueAsDot(final int pValue, final String pExplicit) {
        return "value_" + pValue + "[label=\"#" + pValue + pExplicit + "\"];";
    }

    @SuppressWarnings("unused")
    private static String neqRelationAsDot(final Integer v1, final Integer v2) {
        String targetNode;
        String returnString = "";
        if (v2.equals(0)) {
            targetNode = newNullLabel();
            returnString = targetNode + "[shape=plaintext, label=\"NULL\", fontcolor=\"red\"];\n";
        } else {
            targetNode = "value_" + v2;
        }
        return returnString + "value_" + v1 + " -> " + targetNode
                + "[color=\"red\", fontcolor=\"red\", label=\"neq\"]";
    }

    private String newLineWithOffset(final String pLine) {
        return Strings.repeat(" ", offset) + pLine + "\n";
    }
}