private void MockFunctionData(uint startPosition, uint endPosition, string directory, string fileName) { SbBreakpointLocation location = mockBreakpoint.GetLocationAtIndex(0); SbAddress mockBreakpointAddress = Substitute.For <SbAddress>(); SbAddress mockStartAddress = Substitute.For <SbAddress>(); SbAddress mockFunctionEndAddress = Substitute.For <SbAddress>(); SbAddress mockActualEndAddress = Substitute.For <SbAddress>(); SbLineEntry mockStartLineEntry = Substitute.For <SbLineEntry>(); SbLineEntry mockEndLineEntry = Substitute.For <SbLineEntry>(); ulong address = 0x1234567; location.GetAddress().Returns(mockBreakpointAddress); mockBreakpointAddress.GetFunction().Returns(mockFunction); mockFunction.GetStartAddress().Returns(mockStartAddress); mockFunction.GetEndAddress().Returns(mockFunctionEndAddress); mockFunctionEndAddress.GetLoadAddress(mockTarget).Returns(address); mockTarget.ResolveLoadAddress(address - 1).Returns(mockActualEndAddress); mockStartAddress.GetLineEntry().Returns(mockStartLineEntry); mockActualEndAddress.GetLineEntry().Returns(mockEndLineEntry); mockStartLineEntry.GetLine().Returns(startPosition); mockStartLineEntry.GetDirectory().Returns(directory); mockStartLineEntry.GetFileName().Returns(fileName); mockEndLineEntry.GetLine().Returns(endPosition); }
public int GetCodeContext(ulong codeLocationId, out IDebugCodeContext2 codeContext) { // The codeContext is used, among other things, to link assembly instructions and // source code. The "Go To Source Code" functionality in disassembly view needs this // to be properly implemented. IDebugDocumentContext2 documentContext = null; if (_lineEntryCache.TryGetValue(codeLocationId, out LineEntryInfo lineEntry)) { documentContext = _documentContextFactory.Create(lineEntry); } else { SbAddress address = _target.ResolveLoadAddress(codeLocationId); if (address != null) { lineEntry = address.GetLineEntry(); documentContext = _documentContextFactory.Create(lineEntry); } } string AddressToFuncName() => _target.ResolveLoadAddress(codeLocationId)?.GetFunction()?.GetName() ?? _codeContextName; codeContext = _codeContextFactory.Create(codeLocationId, new Lazy <string>(AddressToFuncName), documentContext, Guid.Empty); return(VSConstants.S_OK); }
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)); }
public List <InstructionInfo> ReadInstructionInfos(SbAddress address, uint count, string flavor) { ReadInstructionInfosResponse response = null; if (connection.InvokeRpc(() => { response = client.ReadInstructionInfos( new ReadInstructionInfosRequest { Target = grpcSbTarget, Address = new GrpcSbAddress { Id = address.GetId() }, Count = count, Flavor = flavor, }); })) { var instructions = new List <InstructionInfo>(); foreach (var instruction in response.Instructions) { instructions.Add(new InstructionInfo( instruction.Address, instruction.Operands, instruction.Comment, instruction.Mnemonic, instruction.SymbolName, FrameInfoUtils.CreateLineEntryInfo(instruction.LineEntry))); } return(instructions); } return(new List <InstructionInfo>()); }
private List <SbInstruction> MockRead(uint instructionsToCreate, uint instructionsToRead, SbAddress startSbAddress, SbMemoryRegionInfo memoryRegion, ulong startAddress = TEST_ADDRESS, bool isMapped = true, bool hasAddress = true, ulong regionEnd = ulong.MaxValue) { var instructions = CreateMockInstructions(instructionsToCreate, startAddress, hasAddress); mockTarget .ReadInstructions(startSbAddress, instructionsToRead, "intel") .Returns(instructions); startSbAddress.GetLoadAddress(mockTarget).Returns(startAddress); mockTarget.ResolveLoadAddress(startAddress).Returns(startSbAddress); memoryRegion.IsMapped().Returns(isMapped); if (!isMapped) { memoryRegion.GetRegionEnd().Returns(regionEnd); } SbMemoryRegionInfo memRegion; mockProcess.GetMemoryRegionInfo(startAddress, out memRegion).Returns( x => { x[1] = memoryRegion; return(mockError); }); return(instructions); }
public bool ApplyPlaceholderProperties(SbModule destModule, PlaceholderModuleProperties properties, RemoteTarget lldbTarget) { long slide = properties.Slide; SbAddress headerAddress = destModule.GetObjectFileHeaderAddress(); if (headerAddress != null) { // For libraries this will generally equal 0, for executables it will equal // |placeholderBaseLoadAddress|. ulong fileBaseAddress = headerAddress.GetFileAddress(); slide -= (long)fileBaseAddress; } SbError error = lldbTarget.SetModuleLoadAddress(destModule, slide); if (error.Fail()) { Trace.WriteLine( $"Failed to set load address on destination module: {error.GetCString()}."); return(false); } if (!destModule.SetPlatformFileSpec(properties.PlatformFileSpec)) { Trace.WriteLine("Failed to set file spec on the destination module."); return(false); } return(true); }
private List <SbInstruction> CreateMockInstructions(uint count, ulong startAddress = TEST_ADDRESS, bool hasAddress = true) { List <SbInstruction> instructions = new List <SbInstruction>(); for (uint i = 0; i < count; i++) { SbAddress mockSbAddress = null; if (hasAddress) { mockSbAddress = Substitute.For <SbAddress>(); mockSbAddress .GetLoadAddress(mockTarget) .Returns(startAddress + i); mockSbAddress.GetSymbol().Returns((SbSymbol)null); mockSbAddress.GetLineEntry().Returns((SbLineEntry)null); } var mockInstruction = Substitute.For <SbInstruction>(); mockInstruction.GetAddress().Returns(mockSbAddress); mockInstruction.GetMnemonic(mockTarget).Returns(TEST_MNEMONIC + i); mockInstruction.GetOperands(mockTarget).Returns(TEST_OPERANDS + i); mockInstruction.GetComment(mockTarget).Returns(TEST_COMMENT); mockInstruction.GetByteSize().Returns(1u); instructions.Add(mockInstruction); } return(instructions); }
public override Task <GetFileAddressResponse> GetFileAddress(GetFileAddressRequest request, ServerCallContext context) { SbAddress address = addressStore.GetObject(request.Address.Id); ulong fileAddress = address.GetFileAddress(); return(Task.FromResult(new GetFileAddressResponse { FileAddress = fileAddress })); }
public BreakpointErrorPair CreateFunctionOffsetBreakpoint(string symbolName, uint offset) { RemoteBreakpoint functionBreakpoint = BreakpointCreateByName(symbolName); if (functionBreakpoint.GetNumLocations() < 1) { return(new BreakpointErrorPair(null, BreakpointError.NoFunctionLocation)); } // At the moment if there are two functions with the same offset will be applied only // for one of them. In base VS 2017 the breakpoint is created only for one // function if there are overloaded functions. SbFunction function = functionBreakpoint.GetLocationAtIndex(0).GetAddress().GetFunction(); // Delete the breakpoint as we don't need it anymore and don't want it to linger _sbTarget.BreakpointDelete(functionBreakpoint.GetId()); if (function == null) { return(new BreakpointErrorPair(null, BreakpointError.NoFunctionFound)); } SbLineEntry startLineEntry = function.GetStartAddress().GetLineEntry(); uint startLine = startLineEntry.GetLine(); // EndAddress points to the first address after the function so we // subtract one from that address and get the corresponding lineEntry. SbAddress endAddress = function.GetEndAddress(); ulong address = endAddress.GetLoadAddress(_sbTarget); endAddress = ResolveLoadAddress(address - 1); uint endLine = endAddress.GetLineEntry().GetLine(); uint newPosition = startLine + offset + 1; if (newPosition > endLine) { return(new BreakpointErrorPair(null, BreakpointError.PositionNotAvailable)); } string fileName = startLineEntry.GetFileName(); string directory = startLineEntry.GetDirectory(); string path = Path.Combine(directory, fileName); RemoteBreakpoint breakpoint = BreakpointCreateByLocation(path, newPosition); return(new BreakpointErrorPair(breakpoint, BreakpointError.Success)); }
public override Task <ResolveLoadAddressResponse> ResolveLoadAddress( ResolveLoadAddressRequest request, ServerCallContext context) { RemoteTarget target = GrpcLookupUtils.GetTarget(request.Target, _targetStore); var response = new ResolveLoadAddressResponse(); SbAddress address = target.ResolveLoadAddress(request.Address); if (address != null) { response.Address = new GrpcSbAddress { Id = _addressStore.AddObject(address), }; } return(Task.FromResult(response)); }
public override Task <GetObjectFileHeaderAddressResponse> GetObjectFileHeaderAddress( GetObjectFileHeaderAddressRequest request, ServerCallContext context) { var module = moduleStore.GetObject(request.Module.Id); SbAddress address = module.GetObjectFileHeaderAddress(); var response = new GetObjectFileHeaderAddressResponse(); if (address != null) { response.Address = new GrpcSbAddress { Id = addressStore.AddObject(address) }; } return(Task.FromResult(response)); }
public void GetCodeContextNullAddressResolution() { SbAddress address = null; var newCodeContext = Substitute.For <IDebugCodeContext2>(); _mockTarget.ResolveLoadAddress(_testAddress).Returns(address); _codeContextFactory.Create(_testAddress, Arg.Any <Lazy <string> >(), null, Guid.Empty) .Returns(newCodeContext); int getCodeContextResult = _disassemblyStream.GetCodeContext(_testAddress, out IDebugCodeContext2 codeContext); Assert.AreEqual(VSConstants.S_OK, getCodeContextResult); Assert.AreEqual(newCodeContext, codeContext); }
public void SetUp() { mockTarget = Substitute.For <SbTarget>(); remoteTarget = new RemoteTargetFactory(new RemoteBreakpointFactory()) .Create(mockTarget); mockAddress = Substitute.For <SbAddress>(); mockProcess = Substitute.For <SbProcess>(); mockMemoryRegion = Substitute.For <SbMemoryRegionInfo>(); mockError = Substitute.For <SbError>(); mockBreakpoint = Substitute.For <SbBreakpoint>(); remoteBreakpoint = new RemoteBreakpointFactory().Create(mockBreakpoint); mockFunction = Substitute.For <SbFunction>(); mockTarget.GetProcess().Returns(mockProcess); }
public void GetBreakpointResolutionNullAddress() { SbBreakpointLocation breakpointLocationNullAddress = Substitute.For <SbBreakpointLocation>(); const SbAddress NULL_ADDRESS = null; breakpointLocationNullAddress.GetAddress().Returns(NULL_ADDRESS); IDebugBoundBreakpoint2 boundBreakpointNullAddress = boundBreakpointFactory.Create( mockPendingBreakpoint, breakpointLocationNullAddress, mockprogram, Guid.Empty); IDebugBreakpointResolution2 breakpointResolutionNullAddress; Assert.AreEqual(VSConstants.E_FAIL, boundBreakpointNullAddress.GetBreakpointResolution( out breakpointResolutionNullAddress)); Assert.AreEqual(null, breakpointResolutionNullAddress); }
public void GetCodeContext() { const ulong newAddress = 0x123456789a; SbAddress address = Substitute.For <SbAddress>(); var documentContext = Substitute.For <IDebugDocumentContext2>(); var newCodeContext = Substitute.For <IDebugCodeContext2>(); _mockTarget.ResolveLoadAddress(newAddress).Returns(address); _documentContextFactory.Create(address.GetLineEntry()).Returns(documentContext); _codeContextFactory .Create(newAddress, Arg.Any <Lazy <string> >(), documentContext, Guid.Empty) .Returns(newCodeContext); Assert.AreEqual(VSConstants.S_OK, _disassemblyStream.GetCodeContext( newAddress, out IDebugCodeContext2 codeContext)); Assert.AreEqual(newCodeContext, codeContext); }
public void ReadEmpty() { uint instructionsToRead = 10; for (uint i = 0; i < instructionsToRead; i++) { var mockInvalidAddress = Substitute.For <SbAddress>(); if (i == 0) { mockAddress = mockInvalidAddress; } ulong address = TEST_ADDRESS + i; MockRead(0, instructionsToRead - i, mockInvalidAddress, mockMemoryRegion, address); } var instructions = remoteTarget.ReadInstructionInfos(mockAddress, instructionsToRead, "intel"); Assert.AreEqual(instructionsToRead, instructions.Count); }
/// <summary> /// Figures out the address of the next instruction and adds it as an invalid instruction /// to |instructions|. /// </summary> /// <returns> The address after the invalid instruction. </returns> ulong AddInvalidInstruction(SbAddress address, List <SbInstruction> sbInstructions, List <InstructionInfo> instructions) { ulong instructionAddress; // Figure out what the address of the invalid instruction should be if (sbInstructions.Count > 0) { // The address of the next instruction should be the address // of the last instruction + its byte size. SbInstruction lastInstruction = sbInstructions[sbInstructions.Count - 1]; instructionAddress = lastInstruction.GetAddress().GetLoadAddress(_sbTarget) + lastInstruction.GetByteSize(); } else { // If we haven't got any instructions yet we use the starting address if (instructions.Count == 0) { instructionAddress = address.GetLoadAddress(_sbTarget); } // If we got no new instructions and we already have some instructions, // use the address of the last instruction + 1 since the last instruction // must have been invalid and therefore the byte size is one. else { instructionAddress = instructions[instructions.Count - 1].Address + 1; } } // Add the invalid instruction, we represent them with setting both the // operands and mnemonic to question marks instructions.Add(new InstructionInfo { Address = instructionAddress, Operands = "??", Mnemonic = "??" }); return(instructionAddress + 1); }
/// <summary> /// Creates unknown/invalid instructions for an unmapped region. /// </summary> /// <returns> The address of the next instruction. </returns> ulong AddUnmappedInstructions(SbAddress address, uint instructionsLeft, SbMemoryRegionInfo memoryRegion, List <InstructionInfo> instructions) { // SbMemoryRegionInfo holds information about the end address even for unmapped // memory regions so we can use that to determine how far we can pad with // invalid/unknown instructions before checking again. ulong memoryRegionEndAddress = memoryRegion.GetRegionEnd(); ulong startAddress = address.GetLoadAddress(_sbTarget); ulong endAddress = Math.Min(memoryRegionEndAddress, startAddress + instructionsLeft); for (ulong currentAddress = startAddress; currentAddress < endAddress; currentAddress++) { instructions.Add(new InstructionInfo { Address = currentAddress, Operands = "??", Mnemonic = "??" }); } return(endAddress); }
public void SetUp() { string name = ""; mockBreakpoint = Substitute.For <RemoteBreakpoint>(); lineEntry = new LineEntryInfo(); mockPendingBreakpoint = Substitute.For <IDebugPendingBreakpoint2>(); mockBreakpointLocation = Substitute.For <SbBreakpointLocation>(); mockAddress = Substitute.For <SbAddress>(); mockAddress.GetLineEntry().Returns(lineEntry); mockBreakpointLocation.GetHitCount().Returns(HIT_COUNT); mockBreakpointLocation.GetLoadAddress().Returns(ADDRESS); mockBreakpointLocation.GetBreakpoint().Returns(mockBreakpoint); mockBreakpointLocation.GetId().Returns(ID); mockBreakpointLocation.GetAddress().Returns(mockAddress); mockprogram = Substitute.For <IDebugProgram2>(); mockDocumentContext = Substitute.For <IDebugDocumentContext2>(); mockDocumentContext.GetName(enum_GETNAME_TYPE.GN_NAME, out name).Returns( x => { x[1] = NAME; return(VSConstants.S_OK); }); mockBreakpointResolution = Substitute.For <IDebugBreakpointResolution2>(); mockDocumentContextFactory = Substitute.For <DebugDocumentContext.Factory>(); mockDocumentContextFactory.Create(lineEntry).Returns(mockDocumentContext); mockCodeContext = Substitute.For <IDebugCodeContext2>(); mockCodeContextFactory = Substitute.For <DebugCodeContext.Factory>(); mockCodeContextFactory.Create(ADDRESS, NAME, mockDocumentContext, Guid.Empty).Returns(mockCodeContext); mockBreakpointResolutionFactory = Substitute.For <DebugBreakpointResolution.Factory>(); mockBreakpointResolutionFactory.Create(mockCodeContext, mockprogram).Returns( mockBreakpointResolution); boundBreakpointFactory = new DebugBoundBreakpoint.Factory(mockDocumentContextFactory, mockCodeContextFactory, mockBreakpointResolutionFactory); boundBreakpoint = boundBreakpointFactory.Create( mockPendingBreakpoint, mockBreakpointLocation, mockprogram, Guid.Empty); }
// Constructor with factories for tests. DebugBoundBreakpoint(DebugDocumentContext.Factory documentContextFactory, DebugCodeContext.Factory codeContextFactory, DebugBreakpointResolution.Factory breakpointResolutionFactory, IDebugPendingBreakpoint2 pendingBreakpoint, SbBreakpointLocation breakpointLocation, IDebugProgram2 program, Guid languageGuid) { _pendingBreakpoint = pendingBreakpoint; _breakpointLocation = breakpointLocation; _enabled = true; _deleted = false; _disabledByPassCount = false; SbAddress address = breakpointLocation.GetAddress(); if (address != null) { LineEntryInfo lineEntry = address.GetLineEntry(); IDebugDocumentContext2 documentContext = null; string name = ""; // |lineEntry| is null if the breakpoint is set on an external function. if (lineEntry != null) { documentContext = documentContextFactory.Create(lineEntry); documentContext.GetName(enum_GETNAME_TYPE.GN_NAME, out name); } IDebugCodeContext2 codeContext = codeContextFactory.Create( breakpointLocation.GetLoadAddress(), name, documentContext, languageGuid); _breakpointResolution = breakpointResolutionFactory.Create(codeContext, program); } else { Trace.WriteLine("Warning: Unable to obtain address from breakpoint location." + " No breakpoint resolution created."); } }
static SourcePosition GetPositionForAddress(SbAddress address) => GetPositionFor(address?.GetLineEntry());
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 int Read(uint numInstructions, enum_DISASSEMBLY_STREAM_FIELDS fields, out uint numInstructionsRead, DisassemblyData[] disassembly) { numInstructionsRead = 0; SbAddress sbAddress = _target.ResolveLoadAddress(_address); if (sbAddress == null) { return(VSConstants.S_FALSE); } bool withSource = ((fields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION) != 0) || ((fields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL) != 0) || ((fields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET) != 0); List <Instruction> instructions = GetInstructions(sbAddress, numInstructions, withSource); for (int i = 0; i < instructions.Count; i++) { Instruction instruction = instructions[i]; _address = instruction.Address; if ((fields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS) != 0) { disassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS; disassembly[i].bstrAddress = $"0x{instruction.Address:x16}"; } if ((fields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID) != 0) { disassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID; disassembly[i].uCodeLocationId = instruction.Address; } if ((fields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE) != 0) { disassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE; disassembly[i].bstrOpcode = instruction.Text; } if ((fields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_SYMBOL) != 0) { if (instruction.Symbol != null) { disassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_SYMBOL; disassembly[i].bstrSymbol = instruction.Symbol; } } if ((fields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL) != 0) { disassembly[i].bstrDocumentUrl = instruction.Document; disassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL; } if ((fields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION) != 0) { if (instruction.HasSource) { disassembly[i].posBeg.dwColumn = 0; disassembly[i].posBeg.dwLine = instruction.StartLine; disassembly[i].posEnd.dwColumn = 0; disassembly[i].posEnd.dwLine = instruction.EndLine; disassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION; } } if ((fields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS) != 0) { disassembly[i].dwFlags = instruction.HasSource ? enum_DISASSEMBLY_FLAGS.DF_HASSOURCE : 0; if (instruction.DocumentChanged) { disassembly[i].dwFlags |= enum_DISASSEMBLY_FLAGS.DF_DOCUMENTCHANGE; } disassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS; } if ((fields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET) != 0) { if (instruction.HasSource) { disassembly[i].dwByteOffset = instruction.ByteOffset; disassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET; } } } numInstructionsRead = Convert.ToUInt32(instructions.Count); return(numInstructionsRead > 0 ? VSConstants.S_OK : VSConstants.S_FALSE); }
public List <InstructionInfo> ReadInstructionInfos(SbAddress address, uint count, string flavor) { throw new NotImplementedTestDoubleException(); }
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 List <SbInstruction> ReadInstructions(SbAddress baseAddress, uint count, string flavor) => _sbTarget.ReadInstructions(baseAddress, count, flavor);
public List <InstructionInfo> ReadInstructionInfos(SbAddress address, uint count, string flavor) { SbProcess process = _sbTarget.GetProcess(); var instructions = new List <InstructionInfo>(); while (instructions.Count < count) { SbMemoryRegionInfo memoryRegion = null; SbError error = process.GetMemoryRegionInfo(address.GetLoadAddress(_sbTarget), out memoryRegion); if (error.Fail()) { Trace.WriteLine("Unable to retrieve memory region info."); return(new List <InstructionInfo>()); } // If the address we are given is not mapped we should not try to disassemble it. if (!memoryRegion.IsMapped()) { uint instructionsLeft = count - (uint)instructions.Count; ulong nextAddress = AddUnmappedInstructions(address, instructionsLeft, memoryRegion, instructions); address = _sbTarget.ResolveLoadAddress(nextAddress); // Continue in case we still need more instructions continue; } List <SbInstruction> sbInstructions = _sbTarget.ReadInstructions(address, count - (uint)instructions.Count, flavor); foreach (SbInstruction sbInstruction in sbInstructions) { SbAddress sbAddress = sbInstruction.GetAddress(); if (sbAddress == null) { // It should never happen that we cannot get an address for an instruction Trace.WriteLine("Unable to retrieve address."); return(new List <InstructionInfo>()); } ulong instructionAddress = sbAddress.GetLoadAddress(_sbTarget); SbSymbol symbol = sbAddress.GetSymbol(); string symbolName = null; // Only set symbolName if it is the start of a function SbAddress startAddress = symbol?.GetStartAddress(); if (startAddress != null && startAddress.GetLoadAddress(_sbTarget) == instructionAddress) { symbolName = symbol.GetName(); } SbLineEntry lineEntry = sbAddress.GetLineEntry(); LineEntryInfo lineEntryInfo = null; if (lineEntry != null) { lineEntryInfo = new LineEntryInfo { FileName = lineEntry.GetFileName(), Directory = lineEntry.GetDirectory(), Line = lineEntry.GetLine(), Column = lineEntry.GetColumn(), }; } // Create a new instruction and fill in the values var instruction = new InstructionInfo { Address = instructionAddress, Operands = sbInstruction.GetOperands(_sbTarget), Comment = sbInstruction.GetComment(_sbTarget), Mnemonic = sbInstruction.GetMnemonic(_sbTarget), SymbolName = symbolName, LineEntry = lineEntryInfo, }; instructions.Add(instruction); } // If we haven't managed to retrieve all the instructions we wanted, add // an invalid instruction and keep going from the next address. if (instructions.Count < count) { ulong nextAddress = AddInvalidInstruction(address, sbInstructions, instructions); // Set the address to the next address after the invalid instruction address = _sbTarget.ResolveLoadAddress(nextAddress); } } return(instructions); }