mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-22 06:02:11 +02:00
Bug 542488: Disassembly support
Change-Id: I8a280fba5147ed3ebd8ecace8b943d3e5350dacf
This commit is contained in:
parent
6fa96ca549
commit
fe13a037b7
11 changed files with 505 additions and 37 deletions
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
||||||
Bundle-ManifestVersion: 2
|
Bundle-ManifestVersion: 2
|
||||||
Bundle-Name: %Bundle-Name
|
Bundle-Name: %Bundle-Name
|
||||||
Bundle-SymbolicName: org.eclipse.cdt.debug.dap;singleton:=true
|
Bundle-SymbolicName: org.eclipse.cdt.debug.dap;singleton:=true
|
||||||
Bundle-Version: 1.0.100.qualifier
|
Bundle-Version: 1.1.0.qualifier
|
||||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||||
Require-Bundle: org.apache.commons.io,
|
Require-Bundle: org.apache.commons.io,
|
||||||
org.eclipse.core.runtime,
|
org.eclipse.core.runtime,
|
||||||
|
@ -20,7 +20,7 @@ Require-Bundle: org.apache.commons.io,
|
||||||
com.google.gson;bundle-version="2.8.2",
|
com.google.gson;bundle-version="2.8.2",
|
||||||
org.eclipse.lsp4j.jsonrpc,
|
org.eclipse.lsp4j.jsonrpc,
|
||||||
org.eclipse.cdt.launch,
|
org.eclipse.cdt.launch,
|
||||||
org.eclipse.lsp4e.debug,
|
org.eclipse.lsp4e.debug;bundle-version="0.11.0",
|
||||||
org.eclipse.debug.core,
|
org.eclipse.debug.core,
|
||||||
org.eclipse.debug.ui,
|
org.eclipse.debug.ui,
|
||||||
org.eclipse.cdt.debug.core,
|
org.eclipse.cdt.debug.core,
|
||||||
|
@ -28,7 +28,8 @@ Require-Bundle: org.apache.commons.io,
|
||||||
org.eclipse.lsp4j.jsonrpc.debug,
|
org.eclipse.lsp4j.jsonrpc.debug,
|
||||||
com.google.guava,
|
com.google.guava,
|
||||||
org.eclipse.xtext.xbase.lib,
|
org.eclipse.xtext.xbase.lib,
|
||||||
org.eclipse.cdt.dsf.gdb;bundle-version="5.7.200"
|
org.eclipse.cdt.dsf.gdb;bundle-version="5.7.200",
|
||||||
|
org.eclipse.cdt.debug.ui
|
||||||
Bundle-Vendor: %Bundle-Vendor
|
Bundle-Vendor: %Bundle-Vendor
|
||||||
Export-Package: org.eclipse.cdt.debug.dap
|
Export-Package: org.eclipse.cdt.debug.dap
|
||||||
Bundle-Activator: org.eclipse.cdt.debug.dap.Activator
|
Bundle-Activator: org.eclipse.cdt.debug.dap.Activator
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<version>1.0.100-SNAPSHOT</version>
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
<artifactId>org.eclipse.cdt.debug.dap</artifactId>
|
<artifactId>org.eclipse.cdt.debug.dap</artifactId>
|
||||||
<packaging>eclipse-plugin</packaging>
|
<packaging>eclipse-plugin</packaging>
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,9 @@
|
||||||
package org.eclipse.cdt.debug.dap;
|
package org.eclipse.cdt.debug.dap;
|
||||||
|
|
||||||
import org.eclipse.core.runtime.IStatus;
|
import org.eclipse.core.runtime.IStatus;
|
||||||
|
import org.eclipse.core.runtime.Platform;
|
||||||
import org.eclipse.core.runtime.Status;
|
import org.eclipse.core.runtime.Status;
|
||||||
|
import org.eclipse.lsp4e.debug.debugmodel.DSPDebugElement;
|
||||||
import org.eclipse.ui.plugin.AbstractUIPlugin;
|
import org.eclipse.ui.plugin.AbstractUIPlugin;
|
||||||
import org.osgi.framework.BundleContext;
|
import org.osgi.framework.BundleContext;
|
||||||
|
|
||||||
|
@ -29,6 +31,8 @@ public class Activator extends AbstractUIPlugin {
|
||||||
public void start(BundleContext context) throws Exception {
|
public void start(BundleContext context) throws Exception {
|
||||||
super.start(context);
|
super.start(context);
|
||||||
plugin = this;
|
plugin = this;
|
||||||
|
|
||||||
|
Platform.getAdapterManager().registerAdapters(new DapDisassemblyBackendFactory(), DSPDebugElement.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -10,6 +10,11 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.debug.dap;
|
package org.eclipse.cdt.debug.dap;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import org.eclipse.lsp4j.debug.DisassembleArguments;
|
||||||
|
import org.eclipse.lsp4j.debug.services.IDebugProtocolServer;
|
||||||
|
import org.eclipse.lsp4j.debug.util.Preconditions;
|
||||||
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
|
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
|
||||||
import org.eclipse.xtext.xbase.lib.Pure;
|
import org.eclipse.xtext.xbase.lib.Pure;
|
||||||
import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
|
import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
|
||||||
|
@ -32,11 +37,8 @@ public class CDTDebugProtocol {
|
||||||
return this.body;
|
return this.body;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBody(@NonNull final MemoryContents address) {
|
public void setBody(@NonNull final MemoryContents body) {
|
||||||
if (address == null) {
|
this.body = Preconditions.checkNotNull(body, "body"); //$NON-NLS-1$
|
||||||
throw new IllegalArgumentException("Property must not be null: body"); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
this.body = address;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -93,11 +95,8 @@ public class CDTDebugProtocol {
|
||||||
return this.data;
|
return this.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setData(@NonNull final String address) {
|
public void setData(@NonNull final String data) {
|
||||||
if (address == null) {
|
this.data = Preconditions.checkNotNull(data, "data"); //$NON-NLS-1$
|
||||||
throw new IllegalArgumentException("Property must not be null: data"); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
this.data = address;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Pure
|
@Pure
|
||||||
|
@ -107,10 +106,7 @@ public class CDTDebugProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAddress(@NonNull final String address) {
|
public void setAddress(@NonNull final String address) {
|
||||||
if (address == null) {
|
this.address = Preconditions.checkNotNull(address, "address"); //$NON-NLS-1$
|
||||||
throw new IllegalArgumentException("Property must not be null: address"); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
this.address = address;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -177,10 +173,7 @@ public class CDTDebugProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAddress(@NonNull final String address) {
|
public void setAddress(@NonNull final String address) {
|
||||||
if (address == null) {
|
this.address = Preconditions.checkNotNull(address, "address"); //$NON-NLS-1$
|
||||||
throw new IllegalArgumentException("Property must not be null: address"); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
this.address = address;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Pure
|
@Pure
|
||||||
|
@ -190,10 +183,7 @@ public class CDTDebugProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLength(@NonNull final Long length) {
|
public void setLength(@NonNull final Long length) {
|
||||||
if (length == null) {
|
this.length = Preconditions.checkNotNull(length, "length"); //$NON-NLS-1$
|
||||||
throw new IllegalArgumentException("Property must not be null: length"); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
this.length = length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Pure
|
@Pure
|
||||||
|
@ -201,11 +191,8 @@ public class CDTDebugProtocol {
|
||||||
return this.offset;
|
return this.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOffset(@NonNull final Long length) {
|
public void setOffset(final Long offset) {
|
||||||
if (length == null) {
|
this.offset = offset;
|
||||||
throw new IllegalArgumentException("Property must not be null: offset"); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
this.offset = length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -256,6 +243,60 @@ public class CDTDebugProtocol {
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An extension to standard {@link DisassembleArguments} that can
|
||||||
|
* be passed to {@link IDebugProtocolServer#disassemble(DisassembleArguments)}
|
||||||
|
*
|
||||||
|
* When endMemoryReference is provided, the disassemble command will return
|
||||||
|
* the minimum number of instructions to get to the end address or number
|
||||||
|
* of lines (instructionCount), whichever is smaller.
|
||||||
|
*/
|
||||||
|
public static class CDTDisassembleArguments extends DisassembleArguments {
|
||||||
|
|
||||||
|
private String endMemoryReference;
|
||||||
|
|
||||||
|
@Pure
|
||||||
|
public String getEndMemoryReference() {
|
||||||
|
return this.endMemoryReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndMemoryReference(final String endMemoryReference) {
|
||||||
|
this.endMemoryReference = endMemoryReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Pure
|
||||||
|
public String toString() {
|
||||||
|
ToStringBuilder b = new ToStringBuilder(this);
|
||||||
|
b.add("memoryReference", this.getMemoryReference()); //$NON-NLS-1$
|
||||||
|
b.add("offset", this.getOffset()); //$NON-NLS-1$
|
||||||
|
b.add("instructionOffset", this.getInstructionOffset()); //$NON-NLS-1$
|
||||||
|
b.add("instructionCount", this.getInstructionCount()); //$NON-NLS-1$
|
||||||
|
b.add("resolveSymbols", this.getResolveSymbols()); //$NON-NLS-1$
|
||||||
|
b.add("endMemoryReference", this.endMemoryReference); //$NON-NLS-1$
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = prime * result + Objects.hash(endMemoryReference);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (!super.equals(obj))
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
CDTDisassembleArguments other = (CDTDisassembleArguments) obj;
|
||||||
|
return Objects.equals(endMemoryReference, other.endMemoryReference);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -94,5 +94,4 @@ public class DapDebugTarget extends DSPDebugTarget implements IMemoryBlockRetrie
|
||||||
}
|
}
|
||||||
return new MemoryBlock(this, expression, bigBaseAddress, context);
|
return new MemoryBlock(this, expression, bigBaseAddress, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,382 @@
|
||||||
|
package org.eclipse.cdt.debug.dap;
|
||||||
|
|
||||||
|
import static org.eclipse.cdt.debug.internal.ui.disassembly.dsf.DisassemblyUtils.DEBUG;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.debug.dap.CDTDebugProtocol.CDTDisassembleArguments;
|
||||||
|
import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.AbstractDisassemblyBackend;
|
||||||
|
import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.AddressRangePosition;
|
||||||
|
import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.DisassemblyUtils;
|
||||||
|
import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.ErrorPosition;
|
||||||
|
import org.eclipse.core.runtime.IAdaptable;
|
||||||
|
import org.eclipse.core.runtime.IStatus;
|
||||||
|
import org.eclipse.core.runtime.Status;
|
||||||
|
import org.eclipse.debug.core.DebugException;
|
||||||
|
import org.eclipse.debug.core.ILaunch;
|
||||||
|
import org.eclipse.debug.core.model.ISourceLocator;
|
||||||
|
import org.eclipse.debug.core.model.IVariable;
|
||||||
|
import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
|
||||||
|
import org.eclipse.jface.text.BadLocationException;
|
||||||
|
import org.eclipse.jface.text.Position;
|
||||||
|
import org.eclipse.lsp4e.debug.debugmodel.DSPDebugTarget;
|
||||||
|
import org.eclipse.lsp4e.debug.debugmodel.DSPStackFrame;
|
||||||
|
import org.eclipse.lsp4j.debug.DisassembleResponse;
|
||||||
|
import org.eclipse.lsp4j.debug.DisassembledInstruction;
|
||||||
|
import org.eclipse.lsp4j.debug.Source;
|
||||||
|
|
||||||
|
@SuppressWarnings("restriction")
|
||||||
|
public class DapDisassemblyBackend extends AbstractDisassemblyBackend {
|
||||||
|
|
||||||
|
private DSPStackFrame dspStackFrame;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsDebugContext(IAdaptable context) {
|
||||||
|
return context instanceof DSPStackFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasDebugContext() {
|
||||||
|
return dspStackFrame != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SetDebugContextResult setDebugContext(IAdaptable context) {
|
||||||
|
assert context instanceof DSPStackFrame;
|
||||||
|
SetDebugContextResult setDebugContextResult = new SetDebugContextResult();
|
||||||
|
if (context instanceof DSPStackFrame) {
|
||||||
|
|
||||||
|
DSPStackFrame newDspStackFrame = (DSPStackFrame) context;
|
||||||
|
setDebugContextResult.contextChanged = !newDspStackFrame.equals(dspStackFrame);
|
||||||
|
dspStackFrame = newDspStackFrame;
|
||||||
|
// sessionId should have been boolean and been hasSessionId, only null/non-null is relevant
|
||||||
|
setDebugContextResult.sessionId = ""; //$NON-NLS-1$
|
||||||
|
if (!setDebugContextResult.contextChanged) {
|
||||||
|
fCallback.gotoFrameIfActive(dspStackFrame.getDepth());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setDebugContextResult.contextChanged = true;
|
||||||
|
setDebugContextResult.sessionId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return setDebugContextResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearDebugContext() {
|
||||||
|
dspStackFrame = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void retrieveFrameAddress(int frame) {
|
||||||
|
fCallback.setUpdatePending(false);
|
||||||
|
fCallback.asyncExec(() -> {
|
||||||
|
int addressBits = dspStackFrame.getFrameInstructionAddressBits();
|
||||||
|
BigInteger address = dspStackFrame.getFrameInstructionAddress();
|
||||||
|
if (addressBits != fCallback.getAddressSize()) {
|
||||||
|
fCallback.addressSizeChanged(addressBits);
|
||||||
|
}
|
||||||
|
if (frame == 0) {
|
||||||
|
fCallback.updatePC(address);
|
||||||
|
} else {
|
||||||
|
fCallback.gotoFrame(frame, address);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFrameLevel() {
|
||||||
|
return dspStackFrame.getDepth();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuspended() {
|
||||||
|
return dspStackFrame.getDebugTarget().isSuspended();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasFrameContext() {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFrameFile() {
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFrameLine() {
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves disassembly based on either (a) start and end address range, or
|
||||||
|
* (b) file, line number, and line count. If the caller specifies both sets
|
||||||
|
* of information, the implementation should honor (b) and ignore (a).
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void retrieveDisassembly(BigInteger startAddress, BigInteger endAddress, String file, int lineNumber,
|
||||||
|
int lines, boolean mixed, boolean showSymbols, boolean showDisassembly, int linesHint) {
|
||||||
|
CDTDisassembleArguments args = new CDTDisassembleArguments();
|
||||||
|
args.setMemoryReference("0x" + startAddress.toString(16)); //$NON-NLS-1$
|
||||||
|
args.setInstructionCount((long) lines);
|
||||||
|
args.setEndMemoryReference("1+0x" + endAddress.toString(16)); //$NON-NLS-1$
|
||||||
|
CompletableFuture<DisassembleResponse> future = dspStackFrame.getDebugProtocolServer().disassemble(args);
|
||||||
|
future.thenAcceptAsync(res -> {
|
||||||
|
fCallback.asyncExec(() -> insertDisassembly(startAddress, endAddress, res, showSymbols, showDisassembly));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param startAddress
|
||||||
|
* an address the caller is hoping will be covered by this
|
||||||
|
* insertion. I.e., [mixedInstructions] may or may not contain
|
||||||
|
* that address; the caller wants to know if it does, and so we
|
||||||
|
* indicate that via our return value. Can be null to indicate n/a,
|
||||||
|
* in which case we return true as long as any instruction was inserted
|
||||||
|
* as long as any instruction was inserted
|
||||||
|
* @param endAddress
|
||||||
|
* cut-off address. Any elements in [mixedInstructions] that
|
||||||
|
* extend beyond this address are ignored.
|
||||||
|
* @param mixedInstructions
|
||||||
|
* @param showSymbols
|
||||||
|
* @param showDisassembly
|
||||||
|
* @return whether [startAddress] was inserted
|
||||||
|
*/
|
||||||
|
private void insertDisassembly(BigInteger startAddress, BigInteger endAddress, DisassembleResponse response,
|
||||||
|
boolean showSymbols, boolean showDisassembly) {
|
||||||
|
if (!fCallback.hasViewer() || dspStackFrame == null) {
|
||||||
|
if (DEBUG) {
|
||||||
|
System.out.println(
|
||||||
|
MessageFormat.format("insertDisassembly ignored at {0} : missing context: [dspStackFrame={1}]", //$NON-NLS-1$
|
||||||
|
DisassemblyUtils.getAddressText(startAddress), dspStackFrame));
|
||||||
|
}
|
||||||
|
if (dspStackFrame == null) {
|
||||||
|
fCallback.setUpdatePending(false);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (DEBUG)
|
||||||
|
System.out.println("insertDisassembly " + DisassemblyUtils.getAddressText(startAddress)); //$NON-NLS-1$
|
||||||
|
boolean updatePending = fCallback.getUpdatePending();
|
||||||
|
assert updatePending;
|
||||||
|
if (!updatePending) {
|
||||||
|
// safe-guard in case something weird is going on
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean insertedAnyAddress = false;
|
||||||
|
try {
|
||||||
|
fCallback.lockScroller();
|
||||||
|
|
||||||
|
AddressRangePosition p = null;
|
||||||
|
Source location = null;
|
||||||
|
DisassembledInstruction[] instructions = response.getInstructions();
|
||||||
|
for (int i = 0; i < instructions.length; ++i) {
|
||||||
|
DisassembledInstruction instruction = instructions[i];
|
||||||
|
if (instruction.getLocation() != null) {
|
||||||
|
location = instruction.getLocation();
|
||||||
|
}
|
||||||
|
assert location != null;
|
||||||
|
String file = null;
|
||||||
|
if (location != null) {
|
||||||
|
file = location.getPath();
|
||||||
|
}
|
||||||
|
Long line = instruction.getLine();
|
||||||
|
int lineNumber = (line == null ? 0 : line.intValue()) - 1;
|
||||||
|
BigInteger address = getAddress(instruction);
|
||||||
|
if (startAddress == null) {
|
||||||
|
startAddress = address;
|
||||||
|
fCallback.setGotoAddressPending(address);
|
||||||
|
}
|
||||||
|
if (p == null || !p.containsAddress(address)) {
|
||||||
|
p = fCallback.getPositionOfAddress(address);
|
||||||
|
}
|
||||||
|
if (p instanceof ErrorPosition && p.fValid) {
|
||||||
|
p.fValid = false;
|
||||||
|
fCallback.getDocument().addInvalidAddressRange(p);
|
||||||
|
} else if (p == null || address.compareTo(endAddress) > 0) {
|
||||||
|
if (DEBUG)
|
||||||
|
System.out.println("Excess disassembly lines at " + DisassemblyUtils.getAddressText(address)); //$NON-NLS-1$
|
||||||
|
return;
|
||||||
|
} else if (p.fValid) {
|
||||||
|
if (DEBUG)
|
||||||
|
System.out.println("Excess disassembly lines at " + DisassemblyUtils.getAddressText(address)); //$NON-NLS-1$
|
||||||
|
if (!p.fAddressOffset.equals(address)) {
|
||||||
|
// override probably unaligned disassembly
|
||||||
|
p.fValid = false;
|
||||||
|
fCallback.getDocument().addInvalidAddressRange(p);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boolean hasSource = false;
|
||||||
|
if (file != null && lineNumber >= 0) {
|
||||||
|
p = fCallback.insertSource(p, address, file, lineNumber);
|
||||||
|
hasSource = fCallback.getStorageForFile(file) != null;
|
||||||
|
}
|
||||||
|
// insert symbol label
|
||||||
|
String functionName;
|
||||||
|
int offset;
|
||||||
|
String symbol = instruction.getSymbol();
|
||||||
|
if (symbol != null) {
|
||||||
|
String[] split = symbol.split("\\+", 2); //$NON-NLS-1$
|
||||||
|
functionName = split[0];
|
||||||
|
if (split.length > 1) {
|
||||||
|
try {
|
||||||
|
offset = Integer.parseInt(split[1]);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
functionName = null;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
if (functionName != null && !functionName.isEmpty() && offset == 0) {
|
||||||
|
p = fCallback.getDocument().insertLabel(p, address, functionName,
|
||||||
|
showSymbols && (!hasSource || showDisassembly));
|
||||||
|
}
|
||||||
|
// determine instruction byte length
|
||||||
|
BigInteger instrLength = null;
|
||||||
|
if (i < instructions.length - 1) {
|
||||||
|
instrLength = getAddress(instructions[i + 1]).subtract(address).abs();
|
||||||
|
} else {
|
||||||
|
// cannot determine length of last instruction
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String funcOffset = instruction.getSymbol();
|
||||||
|
if (funcOffset == null) {
|
||||||
|
funcOffset = ""; //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger opCodes = null;
|
||||||
|
if (instruction.getInstructionBytes() != null) {
|
||||||
|
opCodes = new BigInteger(instruction.getInstructionBytes().replace(" ", ""), 16); //$NON-NLS-1$//$NON-NLS-2$
|
||||||
|
}
|
||||||
|
|
||||||
|
p = fCallback.getDocument().insertDisassemblyLine(p, address, instrLength.intValue(), funcOffset,
|
||||||
|
opCodes, instruction.getInstruction(), file, lineNumber);
|
||||||
|
if (p == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
insertedAnyAddress = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
// should not happen
|
||||||
|
DisassemblyUtils.internalError(e);
|
||||||
|
} finally {
|
||||||
|
fCallback.setUpdatePending(false);
|
||||||
|
if (insertedAnyAddress) {
|
||||||
|
fCallback.updateInvalidSource();
|
||||||
|
fCallback.unlockScroller();
|
||||||
|
fCallback.doPending();
|
||||||
|
fCallback.updateVisibleArea();
|
||||||
|
} else {
|
||||||
|
fCallback.unlockScroller();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigInteger getAddress(DisassembledInstruction instruction) {
|
||||||
|
if (instruction.getAddress().startsWith("0x")) { //$NON-NLS-1$
|
||||||
|
return new BigInteger(instruction.getAddress().substring(2), 16);
|
||||||
|
} else {
|
||||||
|
return new BigInteger(instruction.getAddress(), 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object insertSource(Position pos, BigInteger address, String file, int lineNumber) {
|
||||||
|
ISourceLookupDirector lookupDirector = getSourceLookupDirector();
|
||||||
|
return lookupDirector.getSourceElement(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ISourceLookupDirector getSourceLookupDirector() {
|
||||||
|
if (dspStackFrame == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
DSPDebugTarget debugTarget = dspStackFrame.getDebugTarget();
|
||||||
|
if (debugTarget == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ILaunch launch = debugTarget.getLaunch();
|
||||||
|
if (launch == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ISourceLocator sourceLocator = launch.getSourceLocator();
|
||||||
|
if (sourceLocator instanceof ISourceLookupDirector) {
|
||||||
|
ISourceLookupDirector lookupDirector = (ISourceLookupDirector) sourceLocator;
|
||||||
|
return lookupDirector;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void gotoSymbol(String symbol) {
|
||||||
|
String.class.getClass();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void retrieveDisassembly(String file, int lines, BigInteger endAddress, boolean mixed, boolean showSymbols,
|
||||||
|
boolean showDisassembly) {
|
||||||
|
String.class.getClass();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String evaluateExpression(String expression) {
|
||||||
|
CompletableFuture<IVariable> evaluate = dspStackFrame.evaluate(expression);
|
||||||
|
try {
|
||||||
|
IVariable iVariable = evaluate.get();
|
||||||
|
return iVariable.getValue().getValueString();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return null;
|
||||||
|
} catch (ExecutionException | DebugException | NumberFormatException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
String.class.getClass();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleError(IStatus status) {
|
||||||
|
Activator.log(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigInteger evaluateAddressExpression(String expression, boolean suppressError) {
|
||||||
|
CompletableFuture<IVariable> evaluate = dspStackFrame.evaluate(expression);
|
||||||
|
try {
|
||||||
|
IVariable variable = evaluate.get();
|
||||||
|
return DisassemblyUtils.decodeAddress(variable.getValue().getValueString());
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return null;
|
||||||
|
} catch (ExecutionException | DebugException | NumberFormatException e) {
|
||||||
|
if (!suppressError) {
|
||||||
|
DapDisassemblyBackend.this.handleError(new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0,
|
||||||
|
"Expression does not evaluate to an address (" //$NON-NLS-1$
|
||||||
|
+ e.getMessage() + ")", //$NON-NLS-1$
|
||||||
|
null));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package org.eclipse.cdt.debug.dap;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend;
|
||||||
|
import org.eclipse.core.runtime.IAdapterFactory;
|
||||||
|
import org.eclipse.lsp4e.debug.debugmodel.DSPStackFrame;
|
||||||
|
|
||||||
|
public class DapDisassemblyBackendFactory implements IAdapterFactory {
|
||||||
|
|
||||||
|
private static final Class<?>[] ADAPTERS = { IDisassemblyBackend.class };
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T getAdapter(Object adaptableObject, Class<T> adapterType) {
|
||||||
|
if (IDisassemblyBackend.class.equals(adapterType)) {
|
||||||
|
if (adaptableObject instanceof DSPStackFrame) {
|
||||||
|
DSPStackFrame dspDebugElement = (DSPStackFrame) adaptableObject;
|
||||||
|
if (dspDebugElement.getDebugTarget() instanceof DapDebugTarget) {
|
||||||
|
return (T) new DapDisassemblyBackend();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?>[] getAdapterList() {
|
||||||
|
return ADAPTERS;
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,5 +26,4 @@ public interface ICDTDebugProtocolServer extends IDebugProtocolServer {
|
||||||
default CompletableFuture<MemoryContents> memory(MemoryRequestArguments args) {
|
default CompletableFuture<MemoryContents> memory(MemoryRequestArguments args) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ Export-Package: org.eclipse.cdt.debug.internal.ui;x-friends:="org.eclipse.cdt.ds
|
||||||
org.eclipse.cdt.debug.internal.ui.dialogfields;x-friends:="org.eclipse.cdt.dsf.gdb.ui",
|
org.eclipse.cdt.debug.internal.ui.dialogfields;x-friends:="org.eclipse.cdt.dsf.gdb.ui",
|
||||||
org.eclipse.cdt.debug.internal.ui.dialogs;x-internal:=true,
|
org.eclipse.cdt.debug.internal.ui.dialogs;x-internal:=true,
|
||||||
org.eclipse.cdt.debug.internal.ui.disassembly.commands;x-internal:=true,
|
org.eclipse.cdt.debug.internal.ui.disassembly.commands;x-internal:=true,
|
||||||
org.eclipse.cdt.debug.internal.ui.disassembly.dsf;x-friends:="org.eclipse.cdt.dsf.ui",
|
org.eclipse.cdt.debug.internal.ui.disassembly.dsf;x-friends:="org.eclipse.cdt.dsf.ui,org.eclipse.cdt.debug.dap",
|
||||||
org.eclipse.cdt.debug.internal.ui.disassembly.editor;x-internal:=true,
|
org.eclipse.cdt.debug.internal.ui.disassembly.editor;x-internal:=true,
|
||||||
org.eclipse.cdt.debug.internal.ui.disassembly.viewer;x-internal:=true,
|
org.eclipse.cdt.debug.internal.ui.disassembly.viewer;x-internal:=true,
|
||||||
org.eclipse.cdt.debug.internal.ui.editors;x-internal:=true,
|
org.eclipse.cdt.debug.internal.ui.editors;x-internal:=true,
|
||||||
|
|
|
@ -50,6 +50,19 @@ public class DisassemblyUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BigInteger decodeAddress(String string) {
|
public static BigInteger decodeAddress(String string) {
|
||||||
|
// Handle case where address has type info, such as:
|
||||||
|
// {int (const char *, ...)} 0x7ffff7a48e80 <__printf>
|
||||||
|
if (string.startsWith("{")) { //$NON-NLS-1$
|
||||||
|
int indexOf = string.indexOf('}');
|
||||||
|
if (indexOf >= 0 && indexOf < string.length()) {
|
||||||
|
string = string.substring(indexOf + 1);
|
||||||
|
}
|
||||||
|
indexOf = string.indexOf('<');
|
||||||
|
if (indexOf >= 0) {
|
||||||
|
string = string.substring(0, indexOf);
|
||||||
|
}
|
||||||
|
string = string.trim();
|
||||||
|
}
|
||||||
if (string.startsWith("0x")) { //$NON-NLS-1$
|
if (string.startsWith("0x")) { //$NON-NLS-1$
|
||||||
return new BigInteger(string.substring(2), 16);
|
return new BigInteger(string.substring(2), 16);
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@
|
||||||
<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
|
<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
|
||||||
<unit id="org.eclipse.lsp4e" version="0.0.0"/>
|
<unit id="org.eclipse.lsp4e" version="0.0.0"/>
|
||||||
<unit id="org.eclipse.lsp4e.debug" version="0.0.0"/>
|
<unit id="org.eclipse.lsp4e.debug" version="0.0.0"/>
|
||||||
<repository location="https://download.eclipse.org/lsp4e/releases/0.11.0/"/>
|
<repository location="http://download.eclipse.org/lsp4e/snapshots/"/>
|
||||||
</location>
|
</location>
|
||||||
</locations>
|
</locations>
|
||||||
<targetJRE path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
<targetJRE path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||||
|
|
Loading…
Add table
Reference in a new issue