public int Read(uint dwInstructions, enum_DISASSEMBLY_STREAM_FIELDS dwFields, out uint pdwInstructionsRead, DisassemblyData[] prgDisassembly)
        {
            pdwInstructionsRead = 0;

            if (_method == null)
            {
                return(HResults.E_DISASM_NOTAVAILABLE);
            }

            var method   = _method.Method;
            var insCount = method.Body.Instructions.Count;

            bool wantsDocumentUrl = (dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL) != 0;
            bool wantsPosition    = (dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION) != 0;
            bool wantsByteOffset  = (dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET) != 0;
            bool wantsFlags       = (dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS) != 0;

            for (pdwInstructionsRead = 0; pdwInstructionsRead < dwInstructions; ++pdwInstructionsRead, ++_instructionPointer)
            {
                int ip = _instructionPointer;

                if (ip >= insCount)
                {
                    break;
                }

                var insd = new DisassemblyData();
                var ins  = method.Body.Instructions[ip];


                if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS) != 0)
                {
                    insd.bstrAddress = _method.FormatAddress(ins);
                    insd.dwFields   |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS;
                }

                if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID) != 0)
                {
                    insd.uCodeLocationId = (ulong)ins.Offset;
                    insd.dwFields       |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID;
                }

                if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE) != 0)
                {
                    insd.bstrOpcode = _method.FormatOpCode(ins);
                    insd.dwFields  |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE;
                }

                if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS) != 0)
                {
                    insd.bstrOperands = _method.FormatOperands(ins);
                    insd.dwFields    |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS;
                }

                if (wantsDocumentUrl || wantsPosition || wantsByteOffset || wantsFlags)
                {
                    var source    = _method.FindSourceCode(ins.Offset);
                    var hasSource = source != null && !source.IsSpecial;

                    bool isSameDocAsPrevious, isSameDocPos;

                    if (hasSource)
                    {
                        isSameDocAsPrevious = _prevSource != null &&
                                              !_prevSource.IsSpecial &&
                                              _prevSource.Document.Path == source.Document.Path;
                        isSameDocPos = _prevSource != null && !_prevSource.IsSpecial &&
                                       isSameDocAsPrevious &&
                                       source.Position.CompareTo(_prevSource.Position) == 0;
                    }
                    else
                    {
                        isSameDocAsPrevious = (source == null && _prevSource == null) || (source != null && _prevSource != null && _prevSource.IsSpecial);
                        isSameDocPos        = isSameDocAsPrevious;
                    }

                    if (wantsDocumentUrl && (!isSameDocAsPrevious || _justSeeked))
                    {
                        if (hasSource)
                        {
                            insd.bstrDocumentUrl = "file://" + source.Document.Path;
                            insd.dwFields       |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL;
                        }
                        // how do I clear the document?
                    }

                    int byteOffset = 0;

                    if ((wantsByteOffset || wantsPosition) && hasSource)
                    {
                        if (isSameDocPos)
                        {
                            byteOffset = ins.Offset - _prevSourceInstructionOffset;
                        }
                        else
                        {
                            byteOffset = 0;
                            _prevSourceInstructionOffset = ins.Offset;
                        }
                    }

                    if (wantsPosition && hasSource && !isSameDocPos)
                    {
                        var pos = source.Position;

                        insd.posBeg.dwLine   = (uint)(pos.Start.Line - 1);
                        insd.posBeg.dwColumn = (uint)(pos.Start.Column - 1);
                        insd.posEnd.dwLine   = (uint)(pos.End.Line - 1);
                        insd.posEnd.dwColumn = (uint)(pos.End.Column - 1);

                        if (insd.posEnd.dwLine - insd.posBeg.dwLine > 3) // never show more than 3 lines.
                        {
                            insd.posEnd.dwLine = insd.posBeg.dwLine + 3;
                        }

                        // Is this just me? I have no idea why my VS throws an exception when using this.
                        //insd.dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION;
                    }

                    if (wantsByteOffset && hasSource)
                    {
                        insd.dwByteOffset = (uint)byteOffset;
                        insd.dwFields    |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET;
                    }

                    if (wantsFlags)
                    {
                        if (!isSameDocAsPrevious)
                        {
                            insd.dwFlags |= enum_DISASSEMBLY_FLAGS.DF_DOCUMENTCHANGE;
                        }
                        if (hasSource)
                        {
                            insd.dwFlags |= enum_DISASSEMBLY_FLAGS.DF_HASSOURCE;
                        }

                        //if (_loc.Location.Index == (ulong)ins.Offset)
                        //    insd.dwFlags |= enum_DISASSEMBLY_FLAGS.DF_INSTRUCTION_ACTIVE;


                        insd.dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS;
                    }

                    if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS_SYMBOLS) != 0)
                    {
                        if (!hasSource && !isSameDocPos)
                        {
                            insd.dwFields  |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS_SYMBOLS;
                            insd.bstrSymbol = "(generated instructions)";
                        }
                        else if (hasSource && !isSameDocPos)
                        {
                            // workaround to show something at least
                            if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS_SYMBOLS) != 0)
                            {
                                insd.dwFields  |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS_SYMBOLS;
                                insd.bstrSymbol = "File Position: " + source.Position.Start + " - " + source.Position.End;
                            }
                        }
                    }

                    _justSeeked = false;
                    _prevSource = source;
                }

                prgDisassembly[pdwInstructionsRead] = insd;
            }

            return(pdwInstructionsRead == 0 || _instructionPointer >= insCount ? VSConstants.S_FALSE : VSConstants.S_OK);
        }
Пример #2
0
        public string Format(FormatOptions options)
        {
            var nl = Environment.NewLine;
            var sb = new StringBuilder();

            var body = _methodDef.Body;
            var cfg  = new ControlFlowGraph(body);
            SourceCodePosition lastSource = null;

            _dissassembly.Format = options;

            var embedSource = options.HasFlag(FormatOptions.EmbedSourceCode) || options.HasFlag(FormatOptions.EmbedSourcePositions);

            if (embedSource && _dissassembly.MethodEntry != null)
            {
                var pos = _mapFile.GetSourceCodePositions(_dissassembly.MethodEntry).FirstOrDefault();
                if (pos != null)
                {
                    sb.Append(" // ----- Source Code: ");
                    sb.Append(pos.Document.Path);
                    sb.Append(nl);
                }
            }

            foreach (var block in cfg)
            {
                if (options.HasFlag(FormatOptions.ShowControlFlow))
                {
                    sb.AppendFormat(" // ----- Entry [{0}] Exit [{1}]{2}",
                                    string.Join(", ", block.EntryBlocks.Select(x => _dissassembly.FormatAddress(x.Entry).Trim())),
                                    string.Join(", ", block.ExitBlocks.Select(x => _dissassembly.FormatAddress(x.Entry).Trim())),
                                    nl);
                }


                foreach (var i in block.Instructions)
                {
                    if (embedSource)
                    {
                        var source = _dissassembly.FindSourceCode(i.Offset, false);

                        if (source != null && lastSource != null && source.Document.Path != lastSource.Document.Path)
                        {
                            // print document name.
                            sb.Append(" // ----- ");
                            sb.Append(source.Document.Path);
                            sb.Append(nl);
                            lastSource = null;
                        }

                        if (source == null && lastSource != null)
                        {
                            sb.AppendLine(" // ----- (no source)");
                        }
                        else if (source != null && (lastSource == null || !source.Position.EqualExceptOffset(lastSource.Position)))
                        {
                            if (options.HasFlag(FormatOptions.EmbedSourcePositions))
                            {
                                sb.AppendFormat(" // ----- Position: {0} - {1}{2}", source.Position.Start, source.Position.End, nl);
                            }

                            if (options.HasFlag(FormatOptions.EmbedSourceCode))
                            {
                                string[] lines = GetSourceCodeLines(source);
                                if (lines != null)
                                {
                                    sb.AppendLine(" // " + string.Join(nl + " // ", lines));
                                }
                            }
                        }
                        lastSource = source;
                    }

                    sb.AppendLine(_dissassembly.FormatInstruction(i));
                }
            }
            sb.AppendLine();

            if (body.Exceptions.Any())
            {
                sb.AppendLine("Exception handlers:");
                foreach (var handler in body.Exceptions)
                {
                    sb.AppendFormat("\t{0} - {1}{2}", _dissassembly.FormatAddress(handler.TryStart), _dissassembly.FormatAddress(handler.TryEnd), nl);
                    foreach (var c in handler.Catches)
                    {
                        sb.AppendFormat("\t\t{0} => {1}{2}", c.Type, _dissassembly.FormatAddress(c.Instruction), nl);
                    }
                    if (handler.CatchAll != null)
                    {
                        sb.AppendFormat("\t\t{0} => {1}{2}", "<any>", _dissassembly.FormatAddress(handler.CatchAll), nl);
                    }
                }
                sb.AppendLine();
            }

            if (_mapFile != null)
            {
                var typeEntry = _mapFile.GetTypeByNewName(_methodDef.Owner.Fullname);
                if (typeEntry != null)
                {
                    var methodEntry = typeEntry.FindDexMethod(_methodDef.Name, _methodDef.Prototype.ToSignature());
                    if (methodEntry != null)
                    {
                        _registersToVariableNames = new Dictionary <string, string>();

                        var validParameters = methodEntry.Parameters.Where(x => !string.IsNullOrEmpty(x.Name)).ToList();
                        if (validParameters.Any())
                        {
                            sb.AppendLine("Parameters:");
                            foreach (var p in validParameters)
                            {
                                var registerName = _dissassembly.FormatRegister(p.Register);
                                sb.AppendFormat("\t{0} (r{1}) -> {2}{3}", registerName, p.Register, p.Name, nl);

                                if (!string.IsNullOrEmpty(p.Name))
                                {
                                    _registersToVariableNames.Add(registerName, p.Name);
                                }
                            }
                            sb.AppendLine();
                        }

                        var validVariables = methodEntry.Variables.Where(x => !string.IsNullOrEmpty(x.Name)).ToList();
                        if (validVariables.Any())
                        {
                            sb.AppendLine("Variables:");
                            foreach (var p in validVariables)
                            {
                                var registerName = _dissassembly.FormatRegister(p.Register);
                                sb.AppendFormat("\t{0} -> {1}{2}", registerName, p.Name, nl);
                                if (!string.IsNullOrEmpty(p.Name))
                                {
                                    _registersToVariableNames.Add(registerName, p.Name);
                                }
                            }
                            sb.AppendLine();
                        }

                        sb.AppendLine("Source code positions:");
                        Document lastDocument = null;
                        foreach (var row in _mapFile.GetSourceCodePositions(methodEntry))
                        {
                            if (row.Document != lastDocument)
                            {
                                sb.AppendFormat("\t{0}{1}", row.Document.Path, nl);
                                lastDocument = row.Document;
                            }
                            var pos = row.Position;
                            sb.AppendFormat("\t{0}\t({1},{2}) - ({3},{4}){5}", MethodDisassembly.FormatOffset(pos.MethodOffset), pos.Start.Line, pos.Start.Column, pos.End.Line, pos.End.Column, nl);
                        }
                    }
                }
            }
            return(sb.ToString());
        }