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(); }
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); }
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()); }