/// <summary>
            /// Generate debug info for this entry.
            /// </summary>
            public override void Generate(DebugInfo info, ref int lastLine, ref int lastAddress, ref string lastUrl, ref bool firstPositionEntry, HashSet<Register> startedVariables)
            {
                var documentChanged = false;
                if (!string.IsNullOrEmpty(url) && (url != lastUrl))
                {
                    lastUrl = url;
                    info.DebugInstructions.Add(new DebugInstruction(DebugOpCodes.SetFile, lastUrl));
                    documentChanged = true;
                }

                var lineAdv = line - lastLine;
                var offsetAdv = Offset - lastAddress;

                if ((lineAdv != 0) || documentChanged || firstPositionEntry)
                {
                    // Set position entry
                    DebugOpCodes opcode;
                    if (!TryCalculateSpecialOpcode(lineAdv, offsetAdv, out opcode))
                    {
                        // The line and/or offset advance does not fit in the special opcode, use ADVANCE opcodes
                        if (lineAdv != 0)
                            info.DebugInstructions.Add(new DebugInstruction(DebugOpCodes.AdvanceLine, lineAdv));
                        if (offsetAdv != 0)
                            info.DebugInstructions.Add(new DebugInstruction(DebugOpCodes.AdvancePc, offsetAdv));
                        TryCalculateSpecialOpcode(0, 0, out opcode);
                    }
                    info.DebugInstructions.Add(new DebugInstruction(opcode));

                    lastLine = line;
                    lastAddress = Offset;
                    firstPositionEntry = false;
                }
            }
            /// <summary>
            /// Generate debug info for this entry.
            /// </summary>
            public override void Generate(DebugInfo info, ref int lastLine, ref int lastAddress, ref string lastUrl, ref bool firstPositionEntry, HashSet<Register> startedVariables)
            {
                var offsetAdv = Offset - lastAddress;
                if (offsetAdv > 0)
                {
                    info.DebugInstructions.Add(new DebugInstruction(DebugOpCodes.AdvancePc, offsetAdv));
                    lastAddress = Offset;
                }

                info.DebugInstructions.Add(new DebugInstruction(DebugOpCodes.EndLocal, register));
            }
Ejemplo n.º 3
0
        private void ReadDebugInfo(BinaryReader reader, MethodDefinition mdef, InstructionReader instructionReader,
            uint debugOffset)
        {
            reader.PreserveCurrentPosition(debugOffset, () =>
            {
                var debugInfo = new DebugInfo(mdef.Body);
                mdef.Body.DebugInfo = debugInfo;

                uint lineStart = reader.ReadULEB128();
                debugInfo.LineStart = lineStart;

                uint parametersSize = reader.ReadULEB128();
                for (int i = 0; i < parametersSize; i++)
                {
                    long index = reader.ReadULEB128p1();
                    string name = null;
                    if (index != DexConsts.NoIndex && index >= 0)
                        name = strings[(int) index];
                    debugInfo.Parameters.Add(name);
                }

                while (true)
                {
                    var ins = new DebugInstruction((DebugOpCodes) reader.ReadByte());
                    debugInfo.DebugInstructions.Add(ins);

                    uint registerIndex;
                    uint addrDiff;
                    long nameIndex;
                    long typeIndex;
                    long signatureIndex;
                    int lineDiff;
                    string name;

                    switch (ins.OpCode)
                    {
                        case DebugOpCodes.AdvancePc:
                            // uleb128 addr_diff
                            addrDiff = reader.ReadULEB128();
                            ins.Operands.Add(addrDiff);
                            break;
                        case DebugOpCodes.AdvanceLine:
                            // sleb128 line_diff
                            lineDiff = reader.ReadSLEB128();
                            ins.Operands.Add(lineDiff);
                            break;
                        case DebugOpCodes.EndLocal:
                        case DebugOpCodes.RestartLocal:
                            // uleb128 register_num
                            registerIndex = reader.ReadULEB128();
                            ins.Operands.Add(mdef.Body.Registers[(int) registerIndex]);
                            break;
                        case DebugOpCodes.SetFile:
                            // uleb128p1 name_idx
                            nameIndex = reader.ReadULEB128p1();
                            name = null;
                            if (nameIndex != DexConsts.NoIndex && nameIndex >= 0)
                                name = strings[(int) nameIndex];
                            ins.Operands.Add(name);
                            break;
                        case DebugOpCodes.StartLocalExtended:
                        case DebugOpCodes.StartLocal:
                            // StartLocalExtended : uleb128 register_num, uleb128p1 name_idx, uleb128p1 type_idx, uleb128p1 sig_idx
                            // StartLocal : uleb128 register_num, uleb128p1 name_idx, uleb128p1 type_idx
                            Boolean isExtended = ins.OpCode ==
                                                 DebugOpCodes.
                                                     StartLocalExtended;

                            registerIndex = reader.ReadULEB128();
                            ins.Operands.Add(mdef.Body.Registers[(int) registerIndex]);

                            nameIndex = reader.ReadULEB128p1();
                            name = null;
                            if (nameIndex != DexConsts.NoIndex && nameIndex >= 0)
                                name = strings[(int) nameIndex];
                            ins.Operands.Add(name);

                            typeIndex = reader.ReadULEB128p1();
                            TypeReference type = null;
                            if (typeIndex != DexConsts.NoIndex && typeIndex >= 0)
                                type = typeReferences[(int) typeIndex];
                            ins.Operands.Add(type);

                            if (isExtended)
                            {
                                signatureIndex = reader.ReadULEB128p1();
                                string signature = null;
                                if (signatureIndex != DexConsts.NoIndex && signatureIndex >= 0)
                                    signature = strings[(int) signatureIndex];
                                ins.Operands.Add(signature);
                            }

                            break;
                        case DebugOpCodes.EndSequence:
                            return;
                        case DebugOpCodes.Special:
                        // between 0x0a and 0xff (inclusive)
                        case DebugOpCodes.SetPrologueEnd:
                        case DebugOpCodes.SetEpilogueBegin:
                        default:
                            break;
                    }
                }
            });
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Create debug info for the given (otherwise completed) body.
        /// </summary>
        internal void CreateDebugInfo(MethodBody dbody, RegisterMapper regMapper, DexTargetPackage targetPackage)
        {
            var source = compiledMethod.ILSource;
            if ((source == null) || !source.HasBody || (source.Body.Instructions.Count == 0))
                return;

            // Initialize
            var info = new DebugInfo(dbody);
            info.Parameters.AddRange(dbody.Owner.Prototype.Parameters.Select(x => x.Name ?? "?"));

            // Should be at a better location perhaps
            info.DebugInstructions.Add(new DebugInstruction(DebugOpCodes.SetPrologueEnd));

            // Get instructions with valid sequence points
            var validTuples = dbody.Instructions.Select(x => Tuple.Create(x, x.SequencePoint as ISourceLocation)).Where(x => x.Item2 != null && !x.Item2.IsSpecial).ToList();

            // Assign line numbers
            var lineNumbers = AssignLineNumbers(validTuples.Select(x => x.Item2));

            // Set default document
            string lastUrl = null;
            var setLineStart = true;
            int lastLine = 0;
            int lastOffset = 0;                      
            var firstDocument = validTuples.Select(x => x.Item2).FirstOrDefault(x => x != null && x.Document != null);
            if (firstDocument != null)
            {
                lastUrl = firstDocument.Document;
                lastLine = firstDocument.StartLine;
                info.LineStart = (uint) lastLine;
                setLineStart = false;

                // Set on type or when different in debug info.
                var type = dbody.Owner.Owner;
                if (string.IsNullOrEmpty(type.SourceFile))
                    type.SourceFile = lastUrl;

                if (type.SourceFile != lastUrl)
                {
                    // Make sure the file is set when needed
                    lastUrl = null;
                }
            }

            // Build intermediate list
            var entries = new List<Entry>();

            // Add line numbers
            foreach (var tuple in validTuples)
            {
                var ins = tuple.Item1;
                var seqp = tuple.Item2;
                var lineNumber = GetLineNumber(seqp, lineNumbers);

                // Line number
                if (setLineStart)
                {
                    info.LineStart = (uint)lineNumber;
                    setLineStart = false;
                }

                var url = seqp.Document;
                entries.Add(new PositionEntry(ins.Offset, lineNumber, url));
            }

            // Add variables
            ControlFlowGraph cfg = null;
            foreach (var tuple in regMapper.VariableRegisters)
            {
                var reg = tuple.Register;
                var variable = tuple.Variable;
                if (variable.IsCompilerGenerated)
                    continue;
                var dexType = variable.GetType(targetPackage);
                if (dexType == null)
                    continue;

                // Find out in which basic blocks the variable is live
                cfg = cfg ?? new ControlFlowGraph(dbody);
                var startMap = new Dictionary<BasicBlock, Instruction>();
                foreach (var block in cfg)
                {
                    // First instruction from that first writes to the register.
                    var firstWrite = block.Instructions.FirstOrDefault(reg.IsDestinationIn);
                    if (firstWrite == null)
                        continue;

                    // The variable is valid the first instruction after the first write.
                    Instruction start;
                    if (!firstWrite.TryGetNext(dbody.Instructions, out start))
                        continue;
                    startMap.Add(block, start);
                    block.AddLiveRegisterAtExit(reg);                    
                }

                if (startMap.Count == 0)
                    continue;

                // Generate start-restart-end entries
                VariableEndEntry lastBlockEndEntry = null;
                foreach (var block in cfg)
                {
                    Instruction start;
                    var started = false;
                    if (block.IsLiveAtEntry(reg))
                    {
                        // Live in the entire block
                        if (lastBlockEndEntry == null)
                        {
                            // We have to start/restart
                            entries.Add(new VariableStartEntry(block.Entry.Offset, reg, variable, dexType));
                        }
                        else
                        {
                            // Remove the end-entry of the previous block
                            entries.Remove(lastBlockEndEntry);
                        }
                        started = true;
                    }
                    else if (startMap.TryGetValue(block, out start))
                    {
                        // Live from "start"
                        entries.Add(new VariableStartEntry(start.Offset, reg, variable, dexType));
                        started = true;
                    }

                    Instruction next;
                    lastBlockEndEntry = null;
                    if (started && block.Exit.TryGetNext(dbody.Instructions, out next))
                    {
                        // Add end block
                        entries.Add(lastBlockEndEntry = new VariableEndEntry(next.Offset, reg, variable));
                    }
                }

                // Weave in splilling info
                var spillMappings = regMapper.RegisterSpillingMap.Find(reg).ToList();
                if (spillMappings.Count > 0)
                {
                    foreach (var mapping in spillMappings)
                    {
                        var alreadyStarted = IsStartedAt(entries, variable, mapping.FirstInstruction.Offset);
                        if (alreadyStarted)
                        {
                            // Stop now
                            var prev = mapping.FirstInstruction.GetPrevious(dbody.Instructions);
                            entries.Add(new VariableEndEntry(prev.Offset, mapping.HighRegister, variable));
                        }

                        // Add mappings for low register
                        entries.Add(new VariableStartEntry(mapping.FirstInstruction.Offset, mapping.LowRegister, variable, dexType));
                        entries.Add(new VariableEndEntry(mapping.LastInstruction.Offset, mapping.LowRegister, variable));

                        if (alreadyStarted)
                        {
                            // Restart on high register
                            Instruction next;
                            if (mapping.LastInstruction.TryGetNext(dbody.Instructions, out next))
                            {
                                entries.Add(new VariableStartEntry(next.Offset, mapping.HighRegister, variable, dexType));
                            }
                        }
                    }
                }
            }

            // Generate instructions
            entries.Sort();
            var firstPositionEntry = true;
            var startedVarirables = new HashSet<Register>();
            foreach (var entry in entries)
            {
                entry.Generate(info, ref lastLine, ref lastOffset, ref lastUrl, ref firstPositionEntry, startedVarirables);
            }

            // Terminate
            info.DebugInstructions.Add(new DebugInstruction(DebugOpCodes.EndSequence));

            // Attached
            dbody.DebugInfo = info;
        }