DebugDisassemblyStream(DebugCodeContext.Factory codeContextFactory,
                               DebugDocumentContext.Factory documentContextFactory,
                               enum_DISASSEMBLY_STREAM_SCOPE scope, IDebugCodeContext2 codeContext,
                               RemoteTarget target)
        {
            _codeContextFactory     = codeContextFactory;
            _documentContextFactory = documentContextFactory;
            _scope  = scope;
            _target = target;

            // Used to cache line entries from the last read call
            _lineEntryCache = new Dictionary <ulong, LineEntryInfo>();

            // Extract the address from {codeContext}.
            _address = codeContext.GetAddress();
        }
Esempio n. 2
0
        public int Bind()
        {
            if (_deleted)
            {
                return(AD7Constants.E_BP_DELETED);
            }

            switch ((enum_BP_LOCATION_TYPE)_requestInfo.bpLocation.bpLocationType)
            {
            case enum_BP_LOCATION_TYPE.BPLT_CODE_FILE_LINE:
                IDebugDocumentPosition2 documentPosition =
                    _marshal.GetDocumentPositionFromIntPtr(_requestInfo.bpLocation.unionmember2);
                if (documentPosition.GetFileName(out string fileName) != 0)
                {
                    SetError(enum_BP_ERROR_TYPE.BPET_GENERAL_WARNING, _noSourceFilename);
                    return(VSConstants.S_FALSE);
                }

                TEXT_POSITION[] startPosition = new TEXT_POSITION[1];
                // TODO: Check if we need the end position or not.  This might
                // matter when setting a breakpoint on a comment.  It's possible LLDB will just
                // handle this for us and we don't need to worry about the end position.
                if (documentPosition.GetRange(startPosition, null) != VSConstants.S_OK)
                {
                    SetError(enum_BP_ERROR_TYPE.BPET_GENERAL_WARNING, _noSourceLineNumber);
                    return(VSConstants.S_FALSE);
                }

                // Visual Studio uses a zero based index for line numbers, where LLDB uses a one
                // based index for line numbers.  We need to add one to the line number here to
                // convert visual studio line numbers to LLDB line numbers.
                _lldbBreakpoint =
                    _target.BreakpointCreateByLocation(fileName, startPosition[0].dwLine + 1);
                break;

            case enum_BP_LOCATION_TYPE.BPLT_CODE_FUNC_OFFSET:
                IDebugFunctionPosition2 functionPosition =
                    _marshal.GetFunctionPositionFromIntPtr(_requestInfo.bpLocation.unionmember2);
                uint offset = 0;
                if (functionPosition.GetFunctionName(out string functionName) != 0)
                {
                    SetError(enum_BP_ERROR_TYPE.BPET_GENERAL_WARNING, _noFunctionName);
                    return(VSConstants.S_FALSE);
                }
                MatchCollection matches = _funcOffsetRegex.Matches(functionName);
                if (matches.Count == 1)
                {
                    functionName = matches[0].Groups["name"].Value;
                    string offsetString = matches[0].Groups["offset"].Value;
                    if (!string.IsNullOrWhiteSpace(offsetString))
                    {
                        offset = uint.Parse(offsetString);
                    }
                }

                if (offset > 0)
                {
                    BreakpointErrorPair breakpointErrorPair =
                        _target.CreateFunctionOffsetBreakpoint(functionName, offset);
                    _lldbBreakpoint = breakpointErrorPair.breakpoint;
                    if (_lldbBreakpoint == null)
                    {
                        switch (breakpointErrorPair.error)
                        {
                        case BreakpointError.NoFunctionFound:
                            SetError(enum_BP_ERROR_TYPE.BPET_GENERAL_WARNING, _noFunctionFound);
                            break;

                        case BreakpointError.NoFunctionLocation:
                            SetError(enum_BP_ERROR_TYPE.BPET_GENERAL_WARNING,
                                     _breakpointLocationNotSet);
                            break;

                        case BreakpointError.PositionNotAvailable:
                            SetError(enum_BP_ERROR_TYPE.BPET_GENERAL_WARNING,
                                     _positionNotAvailable);
                            break;

                        default:
                            SetError(enum_BP_ERROR_TYPE.BPET_GENERAL_WARNING,
                                     _positionNotAvailable);
                            break;
                        }
                        return(VSConstants.S_FALSE);
                    }
                }
                else
                {
                    _lldbBreakpoint = _target.BreakpointCreateByName(functionName);
                }
                break;

            case enum_BP_LOCATION_TYPE.BPLT_CODE_CONTEXT:
                IDebugCodeContext2 codeContext =
                    _marshal.GetCodeContextFromIntPtr(_requestInfo.bpLocation.unionmember1);
                if (codeContext == null)
                {
                    SetError(enum_BP_ERROR_TYPE.BPET_GENERAL_WARNING, _noCodeContext);
                    return(VSConstants.S_FALSE);
                }
                ulong address = codeContext.GetAddress();
                _lldbBreakpoint = _target.BreakpointCreateByAddress(address);
                break;

            case enum_BP_LOCATION_TYPE.BPLT_CODE_ADDRESS:
                string strAddress =
                    _marshal.GetStringFromIntPtr(_requestInfo.bpLocation.unionmember4);
                if (strAddress == null)
                {
                    SetError(enum_BP_ERROR_TYPE.BPET_GENERAL_WARNING, _noCodeAddress);
                    return(VSConstants.S_FALSE);
                }
                ulong address2 = Convert.ToUInt64(strAddress, 16);
                _lldbBreakpoint = _target.BreakpointCreateByAddress(address2);
                break;

            default:
                SetError(enum_BP_ERROR_TYPE.BPET_GENERAL_WARNING, _breakpointNotSupported);
                return(VSConstants.S_FALSE);
            }

            if (_lldbBreakpoint == null)
            {
                SetError(enum_BP_ERROR_TYPE.BPET_GENERAL_WARNING, _breakpointNotSet);
                return(VSConstants.S_FALSE);
            }

            UpdateLocations();
            _breakpointManager.RegisterPendingBreakpoint(Self);

            return(_boundBreakpoints.Count == 0
                ? VSConstants.S_FALSE
                : VSConstants.S_OK);
        }
Esempio n. 3
0
        public int SetNextStatement(IDebugStackFrame2 stackFrame, IDebugCodeContext2 codeContext)
        {
            int result = CanSetNextStatement(stackFrame, codeContext);

            if (result != VSConstants.S_OK)
            {
                return(VSConstants.E_FAIL);
            }

            uint   line;
            string filePath;

            codeContext.GetDocumentContext(out IDebugDocumentContext2 documentContext);
            if (documentContext != null)
            {
                documentContext.GetName(enum_GETNAME_TYPE.GN_FILENAME, out filePath);
                var beginPosition = new TEXT_POSITION[1];
                var endPosition   = new TEXT_POSITION[1];
                documentContext.GetStatementRange(beginPosition, endPosition);
                line = beginPosition[0].dwLine + 1;
                Trace.WriteLine($"Settings next statement to {filePath} line {line}.");
            }
            else
            {
                var process = _remoteThread.GetProcess();
                if (process == null)
                {
                    Trace.WriteLine("Error: Failed to obtain process." +
                                    " Unable to set next statement");
                    return(VSConstants.E_FAIL);
                }

                var target = process.GetTarget();
                if (target == null)
                {
                    Trace.WriteLine("Error: Failed to obtain target." +
                                    " Unable to set next statement");
                    return(VSConstants.E_FAIL);
                }

                var address = target.ResolveLoadAddress(codeContext.GetAddress());
                if (address == null)
                {
                    Trace.WriteLine("Error: Failed to obtain address." +
                                    " Unable to set next statement");
                    return(VSConstants.E_FAIL);
                }

                var lineEntry = address.GetLineEntry();
                if (lineEntry == null)
                {
                    Trace.WriteLine("Error: Failed to obtain line entry." +
                                    " Unable to set next statement");
                    return(VSConstants.E_FAIL);
                }

                filePath = Path.Combine(lineEntry.Directory, lineEntry.FileName);
                line     = lineEntry.Line;
                Trace.WriteLine($"Settings next statement to {address} at {filePath} line {line}");
            }

            SbError error = _remoteThread.JumpToLine(filePath, line);

            if (error.Fail())
            {
                Trace.WriteLine(error.GetCString());
                return(VSConstants.E_FAIL);
            }

            return(VSConstants.S_OK);
        }
        public int Seek(enum_SEEK_START seekStart, IDebugCodeContext2 codeContext,
                        ulong codeLocationId, long numInstructions)
        {
            if (seekStart == enum_SEEK_START.SEEK_START_CODECONTEXT)
            {
                _address = codeContext.GetAddress();
            }
            else if (seekStart == enum_SEEK_START.SEEK_START_CODELOCID)
            {
                _address = codeLocationId;
            }

            SbAddress sbAddress = _target.ResolveLoadAddress(_address);

            if (sbAddress == null)
            {
                return(VSConstants.E_FAIL);
            }

            if (numInstructions > 0)
            {
                // seek forward
                numInstructions++;
                List <InstructionInfo> instructions =
                    _target.ReadInstructionInfos(sbAddress, (uint)numInstructions, _flavor);
                if (instructions.Count > 0)
                {
                    numInstructions = Math.Min(numInstructions, instructions.Count);
                    _address        = instructions[(int)numInstructions - 1].Address;
                }
            }
            else if (numInstructions < 0)
            {
                // TODO: Get opcode sizes from LLDB.
                // Hard-code the opcode sizes for x86_64. Currently LLDB doesn't expose this
                // information, and this is the only architecture we support.
                uint minOpcodeSize = 1;
                uint maxOpcodeSize = 15;

                // When seeking backwards we don't know the exact address since x86_64 is a variable
                // size instruction architecture. Instead we figure out the max range to fit a
                // specific number of instructions.
                uint maxRangeForInstructions = (uint)Math.Abs(numInstructions) * maxOpcodeSize;

                // Since x86_64 is a variable size instruction architecture we don't know the exact
                // number of instructions in a specific address range. Assume the smallest opcode
                // size and that will be the number of instructions we need to read.
                uint maxNumberInstructions = maxRangeForInstructions / minOpcodeSize;

                // Using the start address and the max possible range, we can determine the lower
                // bound for where we should start reading instructions from.
                ulong endAddress = _address - maxRangeForInstructions;

                // The instruction where we should start the seek.
                List <InstructionInfo> startInstructionList =
                    _target.ReadInstructionInfos(sbAddress, 1, _flavor);
                if (startInstructionList.Count == 0)
                {
                    Trace.WriteLine(
                        "Failed to seek backwards. Unable to read " +
                        $"instruction at 0x{_address:X} so we have no start point for the seek");
                    return(VSConstants.E_FAIL);
                }

                InstructionInfo startInstruction = startInstructionList[0];

                // We know there is an instruction around the |endAddress| but we don't know exactly
                // where it starts (because variable size instructions). LLDB will stop reading if
                // it runs into a bad instruction. We use that to our advantage and start reading
                // instructions from the |endAddress| + offset until LLDB returns us the number of
                // instructions we requested. We can then be fairly certain |endAddress| + offset is
                // the address to a valid instruction.
                int startIndex = -1;
                List <InstructionInfo> validInstructions = null;
                for (ulong i = 0; i < maxOpcodeSize; i++)
                {
                    ulong     seekAddress               = endAddress + i;
                    SbAddress seekSbAddress             = _target.ResolveLoadAddress(seekAddress);
                    List <InstructionInfo> instructions = _target.ReadInstructionInfos(
                        seekSbAddress, maxNumberInstructions + 1, _flavor);
                    // Shortcut: Continue if we did not get enough instructions.
                    if (instructions == null || instructions.Count < Math.Abs(numInstructions))
                    {
                        continue;
                    }
                    // Only accept the instructions if our start instruction is there.
                    try
                    {
                        startIndex = instructions.BinarySearch(startInstruction,
                                                               new InstructionComparator());
                        if (startIndex >= 0)
                        {
                            validInstructions = instructions;
                            break;
                        }
                    }
                    catch (InvalidOperationException e)
                    {
                        Trace.WriteLine(e);
                    }
                }

                if (startIndex < 0)
                {
                    Trace.WriteLine(
                        "Failed to seek backwards. Unable to find an instruction with " +
                        $"address 0x{_address:X} so we have no start point for the seek");
                    return(VSConstants.E_FAIL);
                }

                // Add the |startIndex| and the negative |numInstructions| to get the index of the
                // instruction to which we want to seek.
                int seekIndex = startIndex + (int)numInstructions;
                if (validInstructions == null || seekIndex < 0 ||
                    seekIndex >= validInstructions.Count)
                {
                    Trace.WriteLine($"Failed to seek backwards. Seek index {seekIndex} is out " +
                                    "of range");
                    return(VSConstants.E_FAIL);
                }
                _address = validInstructions[seekIndex].Address;
            }

            return(VSConstants.S_OK);
        }
 public int GetCodeLocationId(IDebugCodeContext2 codeContext, out ulong codeLocationId)
 {
     codeLocationId = codeContext.GetAddress();
     return(VSConstants.S_OK);
 }
 public void GetAddress()
 {
     Assert.AreEqual(_testPc, _codeContext.GetAddress());
 }