public void ReadOneInstructionWithSource()
        {
            uint numberInstructionsToCreate = 1;
            uint numberInstructionsToRead   = 10;
            var  mockInstructions           = MockRead(numberInstructionsToCreate, numberInstructionsToRead);

            var lineEntry = CreateLineEntry(_testFilename, _testDirectory, 10u, 0u);

            mockInstructions[0].LineEntry = lineEntry;

            var disassembly = new DisassemblyData[numberInstructionsToRead];

            Assert.AreEqual(VSConstants.S_OK,
                            _disassemblyStream.Read((uint)disassembly.Length,
                                                    enum_DISASSEMBLY_STREAM_FIELDS.DSF_ALL,
                                                    out uint numberInstructionsRead, disassembly));
            Assert.AreEqual(1, numberInstructionsRead);
            Assert.AreEqual(enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS,
                            disassembly[0].dwFields);
            Assert.AreEqual(FormatUrl(_testDirectory, _testFilename),
                            disassembly[0].bstrDocumentUrl);
            Assert.AreEqual(9u, disassembly[0].posEnd.dwLine);
            Assert.AreEqual(0u, disassembly[0].posBeg.dwLine);
            Assert.AreEqual(enum_DISASSEMBLY_FLAGS.DF_HASSOURCE |
                            enum_DISASSEMBLY_FLAGS.DF_DOCUMENTCHANGE,
                            disassembly[0].dwFlags);
        }
Пример #2
0
        private DisassemblyData FetchBadInstruction(enum_DISASSEMBLY_STREAM_FIELDS dwFields)
        {
            DisassemblyData dis = new DisassemblyData();

            if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS) != 0)
            {
                dis.dwFields   |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS;
                dis.bstrAddress = EngineUtils.AsAddr(_addr, _engine.DebuggedProcess.Is64BitArch);
            }

            if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID) != 0)
            {
                dis.dwFields       |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID;
                dis.uCodeLocationId = _addr;
            }

            if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_SYMBOL) != 0)
            {
                dis.dwFields  |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_SYMBOL;
                dis.bstrSymbol = string.Empty;
            }

            if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE) != 0)
            {
                dis.dwFields  |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE;
                dis.bstrOpcode = "??";
            }
            return(dis);
        }
        public void ReadTwoInstructionsWithSourceSameLine()
        {
            uint numberInstructionsToCreate = 2;
            uint numberInstructionsToRead   = 10;
            uint firstLine        = 6u;
            var  mockInstructions = MockRead(numberInstructionsToCreate, numberInstructionsToRead);

            var lineEntry = CreateLineEntry(_testFilename, _testDirectory, firstLine + 1u, 0u);

            mockInstructions[0].LineEntry = lineEntry;
            mockInstructions[1].LineEntry = lineEntry;

            var disassembly = new DisassemblyData[numberInstructionsToRead];

            Assert.AreEqual(VSConstants.S_OK,
                            _disassemblyStream.Read((uint)disassembly.Length,
                                                    enum_DISASSEMBLY_STREAM_FIELDS.DSF_ALL,
                                                    out uint numInstructionsRead, disassembly));
            Assert.AreEqual(2, numInstructionsRead);

            Assert.AreEqual(enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS,
                            disassembly[1].dwFields);
            // If the instruction are not on the same line, then the offset from the beginning
            // of the line must not be zero. VS does not seem to care about the precise value,
            // it only seems to care about the zero vs. non-zero distinction.
            Assert.AreNotEqual(0, disassembly[1].dwByteOffset);
            Assert.AreEqual(enum_DISASSEMBLY_FLAGS.DF_HASSOURCE, disassembly[1].dwFlags);
        }
        public void ReadOneInstructionWithoutSource()
        {
            uint numberInstructionsToCreate = 1;
            uint numberInstructionsToRead   = 10;

            MockRead(numberInstructionsToCreate, numberInstructionsToRead);

            var disassembly = new DisassemblyData[numberInstructionsToRead];

            Assert.AreEqual(VSConstants.S_OK,
                            _disassemblyStream.Read((uint)disassembly.Length,
                                                    enum_DISASSEMBLY_STREAM_FIELDS.DSF_ALL,
                                                    out uint numInstructionsRead, disassembly));
            Assert.AreEqual(1, numInstructionsRead);
            Assert.AreEqual(enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS,
                            disassembly[0].dwFields);
            Assert.AreEqual(_testAddress, disassembly[0].uCodeLocationId);
            Assert.AreEqual("0x0000123456789abc", disassembly[0].bstrAddress);
            Assert.AreEqual(
                $"{_testMnemonic + 0} {_testOperands + 0}                 # {_testComment}",
                disassembly[0].bstrOpcode);
            Assert.AreEqual((enum_DISASSEMBLY_FLAGS)0, disassembly[0].dwFlags);
        }
Пример #5
0
        public int Read(uint dwInstructions, enum_DISASSEMBLY_STREAM_FIELDS dwFields, out uint pdwInstructionsRead, DisassemblyData[] prgDisassembly)
        {
            uint iOp = 0;

            IEnumerable<DisasmInstruction> instructions = null;
            _engine.DebuggedProcess.WorkerThread.RunOperation(async () =>
            {
                instructions = await _engine.DebuggedProcess.Disassembly.FetchInstructions(_addr, (int)dwInstructions);
            });

            if (instructions != null)
            {
                foreach (DisasmInstruction instruction in instructions)
                {
                    if (iOp >= dwInstructions)
                    {
                        break;
                    }
                    _addr = instruction.Addr;

                    if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS) != 0)
                    {
                        prgDisassembly[iOp].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS;
                        prgDisassembly[iOp].bstrAddress = instruction.AddressString;
                    }

                    if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID) != 0)
                    {
                        prgDisassembly[iOp].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID;
                        prgDisassembly[iOp].uCodeLocationId = instruction.Addr;
                    }

                    if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_SYMBOL) != 0)
                    {
                        if (instruction.Offset == 0)
                        {
                            prgDisassembly[iOp].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_SYMBOL;
                            prgDisassembly[iOp].bstrSymbol = instruction.Symbol ?? string.Empty;
                        }
                    }

                    if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE) != 0)
                    {
                        prgDisassembly[iOp].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE;
                        prgDisassembly[iOp].bstrOpcode = instruction.Opcode;
                    }

                    iOp++;
                };
            }

            pdwInstructionsRead = iOp;

            return pdwInstructionsRead != 0 ? Constants.S_OK : Constants.S_FALSE;
        }
        public void ReadEmpty()
        {
            uint instructionsToRead = 10;

            MockRead(0, instructionsToRead);

            var disassembly = new DisassemblyData[instructionsToRead];

            Assert.AreEqual(VSConstants.S_FALSE,
                            _disassemblyStream.Read((uint)disassembly.Length,
                                                    enum_DISASSEMBLY_STREAM_FIELDS.DSF_ALL,
                                                    out uint numInstructionsRead, disassembly));
            Assert.AreEqual(0, numInstructionsRead);
        }
        public void ReadFull()
        {
            uint numberInstructions = 20;

            MockRead(numberInstructions, numberInstructions);

            var disassembly = new DisassemblyData[numberInstructions];

            Assert.AreEqual(VSConstants.S_OK,
                            _disassemblyStream.Read((uint)disassembly.Length,
                                                    enum_DISASSEMBLY_STREAM_FIELDS.DSF_ALL,
                                                    out uint numInstructionsRead, disassembly));
            Assert.AreEqual(20, numInstructionsRead);
        }
        public void ReadOneInstructionWithSourceSameFile()
        {
            uint numberInstructionsToCreate = 1;
            uint numberInstructionsToRead   = 10;
            uint previousLine     = 6u;
            uint endLine          = 9u;
            var  mockInstructions = MockRead(numberInstructionsToCreate, numberInstructionsToRead);

            var lineEntry = CreateLineEntry(_testFilename, _testDirectory, endLine + 1u, 0u);

            mockInstructions[0].LineEntry = lineEntry;

            var previousEntry =
                new LineEntryInfo
            {
                Line      = previousLine + 1u,
                Directory = _testDirectory,
                FileName  = _testFilename
            };

            _mockTarget.ResolveLoadAddress(_testAddress - 1).GetLineEntry().Returns(previousEntry);

            var disassembly = new DisassemblyData[numberInstructionsToRead];

            Assert.AreEqual(VSConstants.S_OK,
                            _disassemblyStream.Read((uint)disassembly.Length,
                                                    enum_DISASSEMBLY_STREAM_FIELDS.DSF_ALL,
                                                    out uint numberInstructionsRead, disassembly));
            Assert.AreEqual(1, numberInstructionsRead);
            Assert.AreEqual(enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS,
                            disassembly[0].dwFields);
            Assert.AreEqual(FormatUrl(_testDirectory, _testFilename),
                            disassembly[0].bstrDocumentUrl);
            Assert.AreEqual(previousLine + 1, disassembly[0].posBeg.dwLine);
            Assert.AreEqual(0, disassembly[0].dwByteOffset);
            Assert.AreEqual(enum_DISASSEMBLY_FLAGS.DF_HASSOURCE, disassembly[0].dwFlags);
        }
        public void ReadTwoInstructionsWithSourceDifferentFile()
        {
            uint   numberInstructionsToCreate = 2;
            uint   numberInstructionsToRead   = 10;
            string otherFilename    = "other.cc";
            uint   line             = 5u;
            var    mockInstructions = MockRead(numberInstructionsToCreate, numberInstructionsToRead);

            var firstLineEntry = CreateLineEntry(_testFilename, _testDirectory, line + 1u, 0u);

            mockInstructions[0].LineEntry = firstLineEntry;

            var secondLineEntry = CreateLineEntry(otherFilename, _testDirectory, line + 1u, 0u);

            mockInstructions[1].LineEntry = secondLineEntry;

            var disassembly = new DisassemblyData[numberInstructionsToRead];

            Assert.AreEqual(VSConstants.S_OK,
                            _disassemblyStream.Read((uint)disassembly.Length,
                                                    enum_DISASSEMBLY_STREAM_FIELDS.DSF_ALL,
                                                    out uint numInstructionsRead, disassembly));
            Assert.AreEqual(2, numInstructionsRead);

            Assert.AreEqual(enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET |
                            enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS,
                            disassembly[1].dwFields);
            Assert.AreEqual(FormatUrl(_testDirectory, otherFilename),
                            disassembly[1].bstrDocumentUrl);
            Assert.AreEqual(0u, disassembly[1].posBeg.dwLine);
            Assert.AreEqual(line, disassembly[1].posEnd.dwLine);
            Assert.AreEqual(0, disassembly[1].dwByteOffset);
            Assert.AreEqual(enum_DISASSEMBLY_FLAGS.DF_HASSOURCE |
                            enum_DISASSEMBLY_FLAGS.DF_DOCUMENTCHANGE,
                            disassembly[1].dwFlags);
        }
Пример #10
0
        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);
        }
Пример #11
0
        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;
        }
Пример #12
0
        public static TextPositionTuple GetTextPositionOfFrame(PathConverter converter, IDebugStackFrame2 frame)
        {
            IDebugDocumentContext2 documentContext;
            var source = new Source();

            if (frame.GetDocumentContext(out documentContext) == 0 &&
                documentContext != null)
            {
                var beginPosition = new TEXT_POSITION[1];
                var endPosition   = new TEXT_POSITION[1];
                documentContext.GetStatementRange(beginPosition, endPosition);

                string filePath;
                documentContext.GetName(enum_GETNAME_TYPE.GN_FILENAME, out filePath);

                string convertedFilePath = converter.ConvertDebuggerPathToClient(filePath);
                // save the filename as we need it in any case
                source.Name = Path.GetFileName(convertedFilePath);

                // we have debug info but do we actually have the source code?
                if (File.Exists(convertedFilePath))
                {
                    source.Path = convertedFilePath;
                    int srcline   = converter.ConvertDebuggerLineToClient((int)beginPosition[0].dwLine);
                    int srccolumn = unchecked ((int)(beginPosition[0].dwColumn + 1));

                    return(new TextPositionTuple(source, srcline, srccolumn));
                }
            }

            // this frame is lacking source code
            source.Name   = Path.ChangeExtension(source.Name, ".s") ?? "???";
            source.Path   = null;
            source.Origin = "disassembly";
            ulong startAddress;

            IDebugCodeContext2 codeContext;

            if (frame.GetCodeContext(out codeContext) != HRConstants.S_OK)
            {
                return(null); // we couldn't even find the current instruction, something's really wrong
            }
            var cinfos = new CONTEXT_INFO[1];

            codeContext.GetInfo(enum_CONTEXT_INFO_FIELDS.CIF_ALLFIELDS, cinfos);

            DisassembledRange disRange;

            startAddress = (ulong)Convert.ToInt64(cinfos[0].bstrAddress, 16);

            int  idx     = DisasmRangesDict.FindUpperBound(startAddress);
            bool foundIt = false;
            int  column  = 0;
            int  line    = 0;

            if (idx > 0)
            {
                var kv = DisasmRangesDict.TryGet(idx - 1).Value;
                if (startAddress >= kv.Key && startAddress <= kv.Value.endAddress)
                {
                    disRange = kv.Value;
                    source.SourceReference = disRange.sourceReference;
                    line = kv.Value.dasmData.FirstIndexWhere(d => (ulong)Convert.ToInt64(d.bstrAddress, 16) >= startAddress) ?? 0;
                    ++line;
                    column  = 0;
                    foundIt = true;
                }
            }

            if (!foundIt)
            {
                IDebugThread2 thread;
                frame.GetThread(out thread);
                IDebugProgram2 program;
                thread.GetProgram(out program);
                IDebugDisassemblyStream2 disasmStream;
                program.GetDisassemblyStream(enum_DISASSEMBLY_STREAM_SCOPE.DSS_FUNCTION, codeContext, out disasmStream);
                uint instructionsRead;
                var  dasmData = new DisassemblyData[100];
                if (disasmStream.Read(100, enum_DISASSEMBLY_STREAM_FIELDS.DSF_ALL, out instructionsRead, dasmData) == HRConstants.S_OK)
                {
                    System.Array.Resize(ref dasmData, (int)instructionsRead);
                    source.SourceReference = ++lastSourceReference;
                    DisasmRangesDict.Add(startAddress, new DisassembledRange()
                    {
                        sourceReference = lastSourceReference,
                        endAddress      = (ulong)Convert.ToInt64(dasmData.Last().bstrAddress, 16),
                        dasmData        = dasmData
                    });
                    line   = 1;
                    column = 0;
                }
            }

            return(new TextPositionTuple(source, line, column));
        }
        /// <summary>
        /// Reads instructions starting from the current position in the disassembly stream.
        /// </summary>
        /// <param name="dwInstructions">[in] The number of instructions to disassemble. This value is also the maximum length of the prgDisassembly array.</param>
        /// <param name="dwFields">[in] A combination of flags from the DISASSEMBLY_STREAM_FIELDS enumeration that indicate which fields of prgDisassembly are to be filled out.</param>
        /// <param name="pdwInstructionsRead">[out] Returns the number of instructions actually disassembled.</param>
        /// <param name="prgDisassembly">[out] An array of DisassemblyData structures that is filled in with the disassembled code, one structure per disassembled instruction. The length of this array is dictated by the dwInstructions parameter.</param>
        /// <returns>If successful, returns S_OK; otherwise, returns an error code.</returns>
        /// <remarks>
        /// The maximum number of instructions that are available in the current scope can be obtained by calling the IDebugDisassemblyStream2.GetSize method.
        /// 
        /// The current position where the next instruction is read from can be changed by calling the IDebugDisassemblyStream2.Seek method.
        /// 
        /// The DSF_OPERANDS_SYMBOLS flag can be added to the DSF_OPERANDS flag in the dwFields parameter to indicate that symbol names should be used when disassembling instructions.
        /// </remarks>
        public int Read(uint dwInstructions, enum_DISASSEMBLY_STREAM_FIELDS dwFields, out uint pdwInstructionsRead, DisassemblyData[] prgDisassembly)
        {
            pdwInstructionsRead = 0;

            uint actualInstructions = Math.Min(dwInstructions, (uint)(_disassembledMethod.Instructions.Count - _currentInstructionIndex));

            if (prgDisassembly == null || prgDisassembly.Length < dwInstructions)
                return VSConstants.E_INVALIDARG;

            IMethod method = _executionContext.Location.GetMethod();
            ReadOnlyCollection<ILocalVariable> localVariables = method.GetHasVariableInfo() ? method.GetVariables() : new ReadOnlyCollection<ILocalVariable>(new ILocalVariable[0]);
            ReadOnlyCollection<ConstantPoolEntry> constantPool = _executionContext.Location.GetDeclaringType().GetConstantPool();

            int addressFieldWidth = 1;
            int addressFieldRange = 10 * addressFieldWidth;
            while (addressFieldRange <= _bytecode.Length)
            {
                addressFieldWidth++;
                addressFieldRange *= 10;
            }

            for (int i = 0; i < actualInstructions; i++)
            {
                JavaInstruction instruction = _disassembledMethod.Instructions[_currentInstructionIndex + i];
                int instructionStart = instruction.Offset;
                int instructionSize = instruction.Size;

#if false // bstrAddress is supposed to refer to an absolute offset
                if (dwFields.GetAddress())
                {
                    prgDisassembly[i].bstrAddress = string.Format("{0," + addressFieldWidth + "}", instructionStart);
                    prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS;
                }
#endif

                if (dwFields.GetCodeBytes())
                {
                    prgDisassembly[i].bstrCodeBytes = string.Join(" ", _bytecode.Skip(instructionStart).Take(instructionSize).Select(x => x.ToString("X2")));
                    prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODEBYTES;
                }

                if (dwFields.GetCodeLocationId())
                {
                    prgDisassembly[i].uCodeLocationId = (ulong)instructionStart;
                    prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID;
                }

                if (dwFields.GetOpCode())
                {
                    string depth = _evaluationStackDepths != null ? string.Format("[{0}]", _evaluationStackDepths[_currentInstructionIndex + i]) : string.Empty;
                    prgDisassembly[i].bstrOpcode = string.Format("{0}{1}", depth, instruction.OpCode.Name ?? "???");
                    prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE;
                }

                if (dwFields.GetAddressOffset())
                {
                    prgDisassembly[i].bstrAddressOffset = string.Format("{0," + addressFieldWidth + "}", instructionStart);
                    prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESSOFFSET;
                }

                if (dwFields.GetDocumentUrl())
                {
                    // "For text documents that can be represented as file names, the bstrDocumentUrl
                    // field is filled in with the file name where the source can be found, using the
                    // format file://file name."
                    string sourcePath = _executionContext.Location.GetSourcePath();
                    Uri sourceUri;
                    if (!string.IsNullOrEmpty(sourcePath) && Uri.TryCreate(sourcePath, UriKind.Absolute, out sourceUri))
                    {
                        prgDisassembly[i].bstrDocumentUrl = sourceUri.AbsoluteUri;
                        // if it starts with file:/// one of the / characters will show in disassembly view
                        if (prgDisassembly[i].bstrDocumentUrl.StartsWith("file:///"))
                            prgDisassembly[i].bstrDocumentUrl = "file://" + prgDisassembly[i].bstrDocumentUrl.Substring("file:///".Length);

                        prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL;
                    }
                }

                if (dwFields.GetOperands())
                {
                    prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS;

                    bool includeSymbolNames = dwFields.GetOperandsSymbols();
                    if (includeSymbolNames)
                        prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS_SYMBOLS;

                    // operand 0
                    switch (instruction.OpCode.OperandType)
                    {
                    case JavaOperandType.InlineI1:
                        prgDisassembly[i].bstrOperands = instruction.Operands.InlineSByte.ToString();
                        break;

                    case JavaOperandType.InlineI2:
                        prgDisassembly[i].bstrOperands = instruction.Operands.InlineInt16.ToString();
                        break;

                    case JavaOperandType.InlineShortBranchTarget:
                    case JavaOperandType.InlineBranchTarget:
                        prgDisassembly[i].bstrOperands = (instructionStart + instruction.Operands.Operand1).ToString();
                        break;

                    case JavaOperandType.InlineLookupSwitch:
                        prgDisassembly[i].bstrOperands = "Switch?";
                        break;

                    case JavaOperandType.InlineTableSwitch:
                        prgDisassembly[i].bstrOperands = "TableSwitch?";
                        break;

                    case JavaOperandType.InlineVar:
                    case JavaOperandType.InlineVar_I1:
                        if (includeSymbolNames)
                        {
                            int localIndex = _bytecode[instructionStart + 1];
                            int testLocation = instructionStart;
                            if (instruction.OpCode.StackBehaviorPop != JavaStackBehavior.Pop0)
                            {
                                // this is a store instruction - the variable might not be visible until the following instruction
                                testLocation += instruction.Size;
                            }

                            ILocation currentLocation = _executionContext.Location.GetMethod().GetLocationOfCodeIndex(testLocation);
                            var local = localVariables.SingleOrDefault(variable => variable.GetSlot() == localIndex && variable.GetIsVisible(currentLocation));
                            if (local != null)
                            {
                                prgDisassembly[i].bstrOperands = local.GetName();
                            }
                        }

                        if (string.IsNullOrEmpty(prgDisassembly[i].bstrOperands))
                        {
                            prgDisassembly[i].bstrOperands = "#" + instruction.Operands.VariableSlot.ToString();
                        }

                        break;

                    case JavaOperandType.InlineShortConst:
                    case JavaOperandType.InlineConst:
                    case JavaOperandType.InlineField:
                    case JavaOperandType.InlineMethod:
                    case JavaOperandType.InlineMethod_U1_0:
                    case JavaOperandType.InlineType:
                    case JavaOperandType.InlineType_U1:
                        if (includeSymbolNames)
                        {
                            int index = instruction.Operands.ConstantPoolIndex;
                            var entry = constantPool[index - 1];
                            prgDisassembly[i].bstrOperands = entry.ToString(constantPool);
                        }

                        if (string.IsNullOrEmpty(prgDisassembly[i].bstrOperands))
                        {
                            prgDisassembly[i].bstrOperands = "#" + instruction.Operands.ConstantPoolIndex.ToString();
                        }

                        break;

                    case JavaOperandType.InlineArrayType:
                        prgDisassembly[i].bstrOperands = "T_" + instruction.Operands.ArrayType.ToString().ToUpperInvariant();
                        break;

                    case JavaOperandType.InlineNone:
                        if (includeSymbolNames)
                        {
                            int? localIndex = null;

                            switch (instruction.OpCode.OpCode)
                            {
                            case JavaOpCodeTag.Aload_0:
                            case JavaOpCodeTag.Astore_0:
                            case JavaOpCodeTag.Dload_0:
                            case JavaOpCodeTag.Dstore_0:
                            case JavaOpCodeTag.Fload_0:
                            case JavaOpCodeTag.Fstore_0:
                            case JavaOpCodeTag.Iload_0:
                            case JavaOpCodeTag.Istore_0:
                            case JavaOpCodeTag.Lload_0:
                            case JavaOpCodeTag.Lstore_0:
                                localIndex = 0;
                                break;

                            case JavaOpCodeTag.Aload_1:
                            case JavaOpCodeTag.Astore_1:
                            case JavaOpCodeTag.Dload_1:
                            case JavaOpCodeTag.Dstore_1:
                            case JavaOpCodeTag.Fload_1:
                            case JavaOpCodeTag.Fstore_1:
                            case JavaOpCodeTag.Iload_1:
                            case JavaOpCodeTag.Istore_1:
                            case JavaOpCodeTag.Lload_1:
                            case JavaOpCodeTag.Lstore_1:
                                localIndex = 1;
                                break;

                            case JavaOpCodeTag.Aload_2:
                            case JavaOpCodeTag.Astore_2:
                            case JavaOpCodeTag.Dload_2:
                            case JavaOpCodeTag.Dstore_2:
                            case JavaOpCodeTag.Fload_2:
                            case JavaOpCodeTag.Fstore_2:
                            case JavaOpCodeTag.Iload_2:
                            case JavaOpCodeTag.Istore_2:
                            case JavaOpCodeTag.Lload_2:
                            case JavaOpCodeTag.Lstore_2:
                                localIndex = 2;
                                break;

                            case JavaOpCodeTag.Aload_3:
                            case JavaOpCodeTag.Astore_3:
                            case JavaOpCodeTag.Dload_3:
                            case JavaOpCodeTag.Dstore_3:
                            case JavaOpCodeTag.Fload_3:
                            case JavaOpCodeTag.Fstore_3:
                            case JavaOpCodeTag.Iload_3:
                            case JavaOpCodeTag.Istore_3:
                            case JavaOpCodeTag.Lload_3:
                            case JavaOpCodeTag.Lstore_3:
                                localIndex = 3;
                                break;
                            }

                            if (localIndex.HasValue)
                            {
                                int testLocation = instructionStart;
                                if (instruction.OpCode.StackBehaviorPop != JavaStackBehavior.Pop0)
                                {
                                    // this is a store instruction - the variable might not be visible until the following instruction
                                    testLocation += instruction.Size;
                                }

                                ILocation currentLocation = _executionContext.Location.GetMethod().GetLocationOfCodeIndex(testLocation);
                                var local = localVariables.SingleOrDefault(variable => variable.GetSlot() == localIndex && variable.GetIsVisible(currentLocation));
                                if (local != null)
                                {
                                    prgDisassembly[i].bstrOperands = local.GetName();
                                }
                            }
                        }

                        break;

                    default:
                        prgDisassembly[i].bstrOperands = string.Empty;
                        break;
                    }

                    // operand 1
                    switch (instruction.OpCode.OperandType)
                    {
                    case JavaOperandType.InlineVar_I1:
                        prgDisassembly[i].bstrOperands += " " + instruction.Operands.Increment.ToString();
                        break;

                    case JavaOperandType.InlineMethod_U1_0:
                        prgDisassembly[i].bstrOperands += " " + instruction.Operands.Operand2.ToString();
                        break;

                    case JavaOperandType.InlineType_U1:
                        prgDisassembly[i].bstrOperands += " " + instruction.Operands.Dimensions.ToString();
                        break;

                    default:
                        break;
                    }

                    // operand 2
                    if (instruction.OpCode.OperandType == JavaOperandType.InlineMethod_U1_0)
                    {
                        prgDisassembly[i].bstrOperands += " 0";
                    }
                }

                if (dwFields.GetPosition())
                {
                    try
                    {
                        ILocation location = _executionContext.Location.GetMethod().GetLocationOfCodeIndex(instructionStart);
                        prgDisassembly[i].posBeg.dwLine = (uint)location.GetLineNumber();
                        prgDisassembly[i].posBeg.dwColumn = 0;
                        prgDisassembly[i].posEnd = prgDisassembly[i].posBeg;
                        prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION;
                    }
                    catch (Exception e)
                    {
                        if (ErrorHandler.IsCriticalException(e))
                            throw;

                        prgDisassembly[i].posBeg = default(TEXT_POSITION);
                        prgDisassembly[i].posEnd = default(TEXT_POSITION);
                        prgDisassembly[i].dwFields &= ~enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION;
                    }
                }

                if (dwFields.GetFlags())
                {
                    // TODO: determine when the following condition is met?
                    //   "Indicates that this instruction is one of the next instructions to be executed (there may be more than one)."
                    bool active = false;
                    if (active)
                        prgDisassembly[i].dwFlags |= enum_DISASSEMBLY_FLAGS.DF_INSTRUCTION_ACTIVE;

                    // Check for location information to determine when this condition is met:
                    //   "Indicates that this instruction has source. Some instructions, such as profiling or garbage collection code, have no corresponding source."
                    bool hasSource = prgDisassembly[i].dwFields.GetPosition();
                    if (hasSource)
                        prgDisassembly[i].dwFlags |= enum_DISASSEMBLY_FLAGS.DF_HASSOURCE;

                    // The current single-method disassembly only includes source from a single file, so this is for all but the first line:
                    //   "Indicates that this instruction is in a different document than the previous one."
                    bool documentChange = i == 0 && _currentInstructionIndex == 0;
                    if (documentChange)
                        prgDisassembly[i].dwFlags |= enum_DISASSEMBLY_FLAGS.DF_DOCUMENTCHANGE;

                    // Javac removes code that is statically determined to be unreachable (even in debug mode), so this is false:
                    //   "Indicates that this instruction will not be executed."
                    bool disabled = false;
                    if (disabled)
                        prgDisassembly[i].dwFlags |= enum_DISASSEMBLY_FLAGS.DF_DISABLED;

                    // This is always false in bytecode:
                    //   "Indicates that this instruction is really data (not code)."
                    bool data = false;
                    if (data)
                        prgDisassembly[i].dwFlags |= enum_DISASSEMBLY_FLAGS.DF_DATA;

                    // The Java debugging information format does not include document checksum information
                    bool documentChecksum = false;
                    if (documentChecksum)
                        prgDisassembly[i].dwFlags |= enum_DISASSEMBLY_FLAGS.DF_DOCUMENT_CHECKSUM;

                    prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS;
                }

                if (dwFields.GetByteOffset() && prgDisassembly[i].dwFields.GetPosition())
                {
                    //   "The number of bytes the instruction is from the beginning of the code line."
                    int byteOffset = 0;
                    for (int j = _currentInstructionIndex + i - 1; j >= 0; j--)
                    {
                        JavaInstruction priorInstruction = _disassembledMethod.Instructions[j];
                        try
                        {
                            ILocation location = _executionContext.Location.GetMethod().GetLocationOfCodeIndex(priorInstruction.Offset);
                            if (location.GetLineNumber() != prgDisassembly[i].posBeg.dwLine)
                                break;

                            byteOffset = instruction.Offset - priorInstruction.Offset;
                        }
                        catch (Exception e)
                        {
                            if (ErrorHandler.IsCriticalException(e))
                                throw;

                            break;
                        }
                    }

                    prgDisassembly[i].dwByteOffset = (uint)Math.Max(0, byteOffset);
                    prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET;
                }

                if (dwFields.GetSymbol())
                {
                    switch (instruction.OpCode.OperandType)
                    {
                    case JavaOperandType.InlineLookupSwitch:
                        prgDisassembly[i].bstrSymbol = "// switch";
                        break;

                    case JavaOperandType.InlineTableSwitch:
                        prgDisassembly[i].bstrSymbol = "// table switch";
                        break;

                    default:
                        break;
                    }

                    if (prgDisassembly[i].bstrSymbol != null)
                        prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_SYMBOL;
                }
            }

            _currentInstructionIndex += (int)actualInstructions;
            pdwInstructionsRead = actualInstructions;
            return actualInstructions == dwInstructions ? VSConstants.S_OK : VSConstants.S_FALSE;
        }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public int Read (uint dwInstructions, enum_DISASSEMBLY_STREAM_FIELDS dwFields, out uint pdwInstructionsRead, DisassemblyData [] prgDisassembly)
    {
      // 
      // Reads instructions starting from the current position in the disassembly stream.
      // 

      LoggingUtils.PrintFunction ();

      try
      {
        ulong startAddress = m_codeContext.Address.MemoryAddress;

        ulong endAddress = startAddress + ((ulong)(dwInstructions) * 4); // TODO: 4 for a 32-bit instruction set?

        string disassemblyCommand = string.Format ("-data-disassemble -s 0x{0:X8} -e 0x{1:X8} -- 1", startAddress, endAddress);

        MiResultRecord resultRecord = m_debugger.GdbClient.SendSyncCommand (disassemblyCommand);

        MiResultRecord.RequireOk (resultRecord, disassemblyCommand);

        if (!resultRecord.HasField ("asm_insns"))
        {
          throw new InvalidOperationException ("-data-disassemble result missing 'asm_insns' field");
        }

        MiResultValueList assemblyRecords = (MiResultValueList) resultRecord ["asm_insns"] [0];

        long maxInstructions = Math.Min (assemblyRecords.Values.Count, dwInstructions);

        if (maxInstructions == 0)
        {
          throw new InvalidOperationException ();
        }

        int currentInstruction = 0;

        for (int i = 0; i < assemblyRecords.Values.Count; ++i)
        {
          MiResultValue recordValue = assemblyRecords [i];

          if (recordValue.Variable.Equals ("src_and_asm_line"))
          {
            // 
            // Parse mixed-mode disassembly reports.
            // 

            uint line = recordValue ["line"] [0].GetUnsignedInt ();

            string file = recordValue ["file"] [0].GetString ();

            MiResultValueList lineAsmInstructionValues = (MiResultValueList) recordValue ["line_asm_insn"] [0];

            foreach (MiResultValue instructionValue in lineAsmInstructionValues.Values)
            {
              string address = instructionValue ["address"] [0].GetString ();

              if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS) != 0)
              {
                prgDisassembly [currentInstruction].bstrAddress = address;

                prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS;
              }

              if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESSOFFSET) != 0)
              {
                string offset = instructionValue ["offset"] [0].GetString ();

                prgDisassembly [currentInstruction].bstrAddressOffset = offset;

                prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESSOFFSET;
              }

              if (((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE) != 0) || ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS) != 0) || ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS_SYMBOLS) != 0))
              {
                string inst = instructionValue ["inst"] [0].GetString ();

                string [] operations = inst.Split (new string [] { "\\t" }, StringSplitOptions.None);

                if (operations.Length > 0)
                {
                  prgDisassembly [currentInstruction].bstrOpcode = operations [0];

                  prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE;
                }

                if (operations.Length > 1)
                {
                  prgDisassembly [currentInstruction].bstrOperands = operations [1];

                  prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS;
                }

                if (operations.Length > 2)
                {
                  prgDisassembly [currentInstruction].bstrOperands += " " + operations [2];

                  prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS_SYMBOLS;
                }
              }

              if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_SYMBOL) != 0)
              {
                string functionName = instructionValue ["func-name"] [0].GetString ();

                prgDisassembly [currentInstruction].bstrSymbol = functionName;

                prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_SYMBOL;
              }

              if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID) != 0)
              {
                DebuggeeAddress instructionAddress = new DebuggeeAddress (address);

                prgDisassembly [currentInstruction].uCodeLocationId = instructionAddress.MemoryAddress;

                prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID;
              }

              if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION) != 0)
              {
                prgDisassembly [currentInstruction].posBeg.dwLine = line;

                prgDisassembly [currentInstruction].posBeg.dwColumn = 0;

                prgDisassembly [currentInstruction].posEnd.dwLine = line;

                prgDisassembly [currentInstruction].posEnd.dwColumn = uint.MaxValue;

                prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION;
              }

              if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL) != 0)
              {
                prgDisassembly [currentInstruction].bstrDocumentUrl = "file://" + file;

                prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL;
              }

              if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET) != 0)
              {
                uint offset = instructionValue ["offset"] [0].GetUnsignedInt ();

                prgDisassembly [currentInstruction].dwByteOffset = offset;

                prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET;
              }

              if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS) != 0)
              {
                prgDisassembly [currentInstruction].dwFlags |= enum_DISASSEMBLY_FLAGS.DF_HASSOURCE;

                prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS;
              }

              if (++currentInstruction >= maxInstructions)
              {
                break;
              }
            }
          }
        }

        pdwInstructionsRead = (uint) currentInstruction;

        return Constants.S_OK;
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        pdwInstructionsRead = 0;

        return Constants.E_FAIL;
      }
    }