private void addGlobalObjectSubgraph(CLangSMG pSmg, StringBuilder pSb) {
   pSb.append(newLineWithOffset("subgraph cluster_global{"));
   offset += 2;
   pSb.append(newLineWithOffset("label=\"Global objects\";"));
   pSb.append(newLineWithOffset(smgScopeFrameAsDot(pSmg.getGlobalObjects(), "global", null)));
   offset -= 2;
   pSb.append(newLineWithOffset("}"));
 }
  private static String smgObjectAsDot(SMGObject pObject, CLangSMG pSmg) {

    String valid = pSmg.isObjectValid(pObject) ? "" : " : invalid ";
    return pObject.getLabel()
        + " [ shape=rectangle, label = \""
        + pObject.toString()
        + valid
        + "\"];";
  }
  private String smgHVEdgeAsDot(SMGEdgeHasValue pEdge, CLangSMG smg) {
    SMGObject obj = pEdge.getObject();
    Location location = Location.valueOf(obj, smg.getFunctionName(obj));

    return locationIndex.get(location)
        + " -> value_"
        + pEdge.getValue()
        + "[label=\"["
        + pEdge.getOffset()
        + "]\"];";
  }
  private String smgPTEdgeAsDot(SMGEdgePointsTo pEdge, CLangSMG smg) {

    SMGObject obj = pEdge.getObject();
    Location location = Location.valueOf(obj, smg.getFunctionName(obj));

    return "value_"
        + pEdge.getValue()
        + " -> "
        + locationIndex.get(location)
        + "[label=\"+"
        + pEdge.getOffset()
        + "b\"];";
  }
  private void addStackSubgraph(CLangSMG pSmg, StringBuilder pSb) {
    pSb.append(newLineWithOffset("subgraph cluster_stack {"));
    offset += 2;
    pSb.append(newLineWithOffset("label=\"Stack\";"));

    int i = 0;
    for (CLangStackFrame stack_item : pSmg.getStackFrames()) {
      addStackItemSubgraph(stack_item, pSb, i);
      i++;
    }
    offset -= 2;
    pSb.append(newLineWithOffset("}"));
  }
  public String smgAsDot(CLangSMG smg, String name, 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);

    for (SMGObject heapObject : smg.getHeapObjects()) {
      sb.append(newLineWithOffset(smgObjectAsDot(heapObject, smg)));
      locationIndex.put(Location.valueOf(heapObject), heapObject.getLabel());
    }

    // This only works after creating all heap Objects,
    // because we can't differentiate between global Memlocs and heap Memlocs
    addGlobalObjectSubgraph(smg, sb);

    Map<Integer, MemoryLocation> coveredBySMG = new HashMap<>();
    Set<MemoryLocation> coveredMemloc = new HashSet<>();

    for (SMGEdgeHasValue edge : smg.getHVEdges()) {

      SMGObject obj = edge.getObject();
      String functionName = smg.getFunctionName(obj);
      MemoryLocation memloc =
          smgState.resolveMemLoc(SMGAddress.valueOf(obj, edge.getOffset()), functionName);
      if (explicitState.contains(memloc)) {
        coveredBySMG.put(edge.getValue(), memloc);
        coveredMemloc.add(memloc);
      }
    }

    for (int value : smg.getValues()) {
      sb.append(newLineWithOffset(smgValueAsDot(value, coveredBySMG)));
    }

    Set<MemoryLocation> notCoveredBySMG = new HashSet<>();

    for (MemoryLocation memloc : explicitState.getTrackedMemoryLocations()) {
      // We don't consider values from the old Nomenclature in explicit cpa
      if (!coveredMemloc.contains(memloc) && !memloc.getAsSimpleString().contains("->")) {
        sb.append(newLineWithOffset(explicitValueAsDot(memloc)));
        notCoveredBySMG.add(memloc);
      }
    }

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

    for (MemoryLocation memloc : notCoveredBySMG) {
      sb.append(newLineWithOffset(memlocAsDot(memloc)));
    }

    for (SMGEdgePointsTo edge : smg.getPTEdges().values()) {
      sb.append(newLineWithOffset(smgPTEdgeAsDot(edge, smg)));
    }

    sb.append("}");

    return sb.toString();
  }