public override Task <ReadInstructionInfosResponse> ReadInstructionInfos(
            ReadInstructionInfosRequest request, ServerCallContext context)
        {
            RemoteTarget           target       = GrpcLookupUtils.GetTarget(request.Target, _targetStore);
            SbAddress              address      = _addressStore.GetObject(request.Address.Id);
            var                    response     = new ReadInstructionInfosResponse();
            List <InstructionInfo> instructions =
                target.ReadInstructionInfos(address, request.Count, request.Flavor);

            if (instructions != null)
            {
                foreach (InstructionInfo instruction in instructions)
                {
                    var instructionInfo = new GrpcInstructionInfo {
                        Address    = instruction.Address, Operands = instruction.Operands ?? "",
                        Comment    = instruction.Comment ?? "", Mnemonic = instruction.Mnemonic ?? "",
                        SymbolName = instruction.SymbolName ?? ""
                    };
                    if (instruction.LineEntry != null)
                    {
                        instructionInfo.LineEntry = new GrpcLineEntryInfo {
                            FileName  = instruction.LineEntry.FileName ?? "",
                            Directory = instruction.LineEntry.Directory ?? "",
                            Line      = instruction.LineEntry.Line, Column = instruction.LineEntry.Column
                        };
                    }
                    response.Instructions.Add(instructionInfo);
                }
            }
            return(Task.FromResult(response));
        }
        List <Instruction> GetInstructions(SbAddress sbAddress, uint numInstructions,
                                           bool withSource)
        {
            _lineEntryCache.Clear();
            var instructions = new List <Instruction>();

            // If we need source information, we look at the previous instruction to find out
            // if it is on the same line and/or in the same file.
            var position = SourcePosition.Empty;

            if (withSource)
            {
                // Find previous instruction and initialize lineAddress and lastLine here.
                SbAddress previousSbAddress =
                    _target.ResolveLoadAddress(sbAddress.GetLoadAddress(_target) - 1);
                if (previousSbAddress != null)
                {
                    position = GetPositionForAddress(previousSbAddress);
                }
            }

            uint numInstructionsRead = 0;
            List <InstructionInfo> cachedInstructions =
                _target.ReadInstructionInfos(sbAddress, numInstructions, _flavor);

            for (int i = 0; i < cachedInstructions.Count; i++)
            {
                Instruction currentInstruction = new Instruction();

                if (numInstructionsRead >= numInstructions)
                {
                    break;
                }

                numInstructionsRead++;

                InstructionInfo instruction = cachedInstructions[i];

                _lineEntryCache.Add(instruction.Address, instruction.LineEntry);

                currentInstruction.Address = instruction.Address;

                // Since Visual Studio doesn't do a good job formatting opcode and operands, in
                // addition to not providing a field to show instruction comments, do all the
                // formatting ourselves and put the entire string in the opcode field.
                string operands          = instruction.Operands;
                string comment           = instruction.Comment;
                string instructionString = $"{instruction.Mnemonic,-10}";
                if (string.IsNullOrEmpty(comment))
                {
                    instructionString += $" {operands}";
                }
                else
                {
                    instructionString += $" {operands,-30} # {comment}";
                }
                currentInstruction.Text = instructionString;

                if (!string.IsNullOrEmpty(instruction.SymbolName))
                {
                    currentInstruction.Symbol = instruction.SymbolName;
                }

                // If we so far believe we should get source position, let us get it here.
                if (withSource)
                {
                    SourcePosition lastPosition = position;
                    position = GetPositionFor(instruction.LineEntry);
                    WritePositionToInstruction(lastPosition, position, i == 0,
                                               ref currentInstruction);
                }
                instructions.Add(currentInstruction);
            }
            return(instructions);
        }
        public void SeekNegativeInvalidStartInstruction()
        {
            var mockAddress = Substitute.For <SbAddress>();

            _mockTarget.ResolveLoadAddress(_testAddress).Returns(mockAddress);
            _mockTarget.ReadInstructionInfos(mockAddress, 1, _flavor)
            .Returns(new List <InstructionInfo>());
            Assert.AreEqual(
                VSConstants.E_FAIL,
                _disassemblyStream.Seek(enum_SEEK_START.SEEK_START_CURRENT, null, 0, -10));

            // Location shouldn't change.
            _disassemblyStream.GetCurrentLocation(out ulong newLocation);
            Assert.AreEqual(_testAddress, newLocation);
        }
        public void ReadFull()
        {
            uint numberInstructions = 20;

            MockRead(numberInstructions, numberInstructions, mockAddress, mockMemoryRegion);

            var instructions = remoteTarget.ReadInstructionInfos(mockAddress, numberInstructions,
                                                                 "intel");

            Assert.AreEqual(numberInstructions, instructions.Count);
            Assert.IsNull(instructions[0].SymbolName);
        }