public static ErrorTrace undoUnrolling(ErrorTrace trace)
        {
            // The heuristic used here is to get rid of the "#num" sign in the labels.
            // We assume that is the only way that Boogie.UnrollLoops changes the labels
            ErrorTrace ret = new ErrorTrace(trace.procName);

            for (int i = 0, n = trace.Blocks.Count; i < n; i++)
            {
                ret.addBlock(new ErrorTraceBlock(sanitizeLabel(trace.Blocks[i].blockName)));

                foreach (var c in trace.Blocks[i].Cmds)
                {
                    if (c is CallInstr)
                    {
                        var cc = c as CallInstr;
                        if (cc.calleeTrace != null)
                        {
                            ret.addInstr(new CallInstr(undoUnrolling(cc.calleeTrace), cc.asyncCall, cc.info));
                            continue;
                        }
                    }
                    ret.addInstr(c);
                }
            }
            if (trace.returns)
            {
                ret.addReturn();
            }

            return(ret);
        }
        public ErrorTrace mapBackTrace(ErrorTrace trace)
        {
            if (!dict.ContainsKey(trace.procName))
            {
                // missing transformations are assumed to be identity
                var ret = new ErrorTrace(getSrcProcName(trace.procName));

                foreach (var blk in trace.Blocks)
                {
                    ret.addBlock(new ErrorTraceBlock(blk.blockName));
                    foreach (var c in blk.Cmds)
                    {
                        if (c.isCall())
                        {
                            CallInstr cc = c as CallInstr;
                            if (cc.calleeTrace != null)
                            {
                                var t = mapBackTrace(cc.calleeTrace);
                                ret.addInstr(new CallInstr(t, cc.asyncCall, cc.info));
                                continue;
                            }
                        }
                        ret.addInstr(c);
                    }
                }

                if (trace.returns)
                {
                    ret.addReturn(trace.raisesException);
                }

                return(ret);
            }
            return(dict[trace.procName].mapBackTrace(trace, this));
        }
        private ErrorTrace mapBackTraceInline(ErrorTrace trace)
        {
            Debug.Assert(trace.isIntra());

            Program inputProg = inlineInput.getProgram();

            var nameImplMap = BoogieUtil.nameImplMapping(inputProg);
            var traceLabels = trace.getBlockLabels();

            var            stack     = new List <WorkItemR>();
            Implementation startImpl = getImpl(trace.procName, nameImplMap);

            Debug.Assert(traceLabels[0] == startImpl.Blocks[0].Label);
            var curr = new WorkItemR(startImpl, traceLabels[0]);

            // This variable keeps our current position in traceLabels
            int ecount = 0;
            // This variable keeps our current position in traceLabels[ecount].Cmds
            int icount = 0;

            var ret = new ErrorTrace(trace.procName);

            ret.addBlock(new ErrorTraceBlock(traceLabels[0]));

            // We will walk over the input program, trying to cover the same path as
            // trace, knowing that trace represents an inlined path
            while (true)
            {
                // Reached the end of the path?
                if (ecount == traceLabels.Count)
                {
                    break;
                }

                //Console.WriteLine(curr.impl.Name + ": " + curr.label);

                // Reached the end of the current block?
                if (curr.count == curr.block.Cmds.Count)
                {
                    ecount++;
                    icount = 0;
                    if (ecount == traceLabels.Count)
                    {
                        break;
                    }

                    // Move onto the next block
                    TransferCmd tc = curr.block.TransferCmd;
                    if (tc is ReturnCmd)
                    {
                        ret.addReturn();

                        if (stack.Count == 0)
                        {
                            // We're done
                            Debug.Assert(ecount == traceLabels.Count);
                            break;
                        }
                        curr = stack[0];
                        stack.RemoveAt(0);

                        // An inlined procedure ends with "Return" label
                        Debug.Assert(inlinedLabelMatches("Return", traceLabels[ecount]));

                        ecount++;
                        icount = 0;
                        Debug.Assert(traceLabels[ecount].Contains(curr.block.Label));

                        continue;
                    }

                    if (tc is GotoCmd)
                    {
                        List <String> targets = (tc as GotoCmd).labelNames;
                        string        target  = matchInlinedLabelNames(targets, traceLabels[ecount]);
                        curr = new WorkItemR(curr.impl, target);
                        ret.addBlock(new ErrorTraceBlock(curr.label));
                        continue;
                    }

                    // Unknown transfer command
                    Debug.Assert(false);
                }

                // We have to continue in the same block
                Cmd c = curr.block.Cmds[curr.count];
                curr.count++;

                if (!(c is CallCmd))
                {
                    ret.addInstr(new IntraInstr(getInfo(trace, ecount, icount)));
                    icount++;
                    continue;
                }

                // We're at a procedure call
                CallCmd cc = c as CallCmd;

                // If this is a call to a procedure without implementation, then skip
                if (!nameImplMap.ContainsKey(cc.Proc.Name))
                {
                    ret.addInstr(new CallInstr(cc.Proc.Name, null, false, getInfo(trace, ecount, icount)));
                    icount++;
                    continue;
                }

                Implementation callee = getImpl(cc.Proc.Name, nameImplMap);
                string         label  = callee.Blocks[0].Label;
                // The first label in a inlined procedure is always called Entry
                ecount++;
                Debug.Assert(inlinedLabelMatches("Entry", traceLabels[ecount]));

                ecount++;
                icount = 0;
                Debug.Assert(inlinedLabelMatches(label, traceLabels[ecount]));

                WorkItemR next = new WorkItemR(callee, label);
                stack.Insert(0, curr);
                curr = next;

                ret.addCall(callee.Name);
                ret.addBlock(new ErrorTraceBlock(curr.label));
            }
            return(ret);
        }