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-Name: %Bundle-Name
|
||||
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
|
||||
Require-Bundle: org.apache.commons.io,
|
||||
org.eclipse.core.runtime,
|
||||
|
@ -20,7 +20,7 @@ Require-Bundle: org.apache.commons.io,
|
|||
com.google.gson;bundle-version="2.8.2",
|
||||
org.eclipse.lsp4j.jsonrpc,
|
||||
org.eclipse.cdt.launch,
|
||||
org.eclipse.lsp4e.debug,
|
||||
org.eclipse.lsp4e.debug;bundle-version="0.11.0",
|
||||
org.eclipse.debug.core,
|
||||
org.eclipse.debug.ui,
|
||||
org.eclipse.cdt.debug.core,
|
||||
|
@ -28,7 +28,8 @@ Require-Bundle: org.apache.commons.io,
|
|||
org.eclipse.lsp4j.jsonrpc.debug,
|
||||
com.google.guava,
|
||||
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
|
||||
Export-Package: org.eclipse.cdt.debug.dap
|
||||
Bundle-Activator: org.eclipse.cdt.debug.dap.Activator
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<version>1.0.100-SNAPSHOT</version>
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
<artifactId>org.eclipse.cdt.debug.dap</artifactId>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
package org.eclipse.cdt.debug.dap;
|
||||
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.lsp4e.debug.debugmodel.DSPDebugElement;
|
||||
import org.eclipse.ui.plugin.AbstractUIPlugin;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
|
@ -29,6 +31,8 @@ public class Activator extends AbstractUIPlugin {
|
|||
public void start(BundleContext context) throws Exception {
|
||||
super.start(context);
|
||||
plugin = this;
|
||||
|
||||
Platform.getAdapterManager().registerAdapters(new DapDisassemblyBackendFactory(), DSPDebugElement.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,6 +10,11 @@
|
|||
*******************************************************************************/
|
||||
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.xtext.xbase.lib.Pure;
|
||||
import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
|
||||
|
@ -32,11 +37,8 @@ public class CDTDebugProtocol {
|
|||
return this.body;
|
||||
}
|
||||
|
||||
public void setBody(@NonNull final MemoryContents address) {
|
||||
if (address == null) {
|
||||
throw new IllegalArgumentException("Property must not be null: body"); //$NON-NLS-1$
|
||||
}
|
||||
this.body = address;
|
||||
public void setBody(@NonNull final MemoryContents body) {
|
||||
this.body = Preconditions.checkNotNull(body, "body"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -93,11 +95,8 @@ public class CDTDebugProtocol {
|
|||
return this.data;
|
||||
}
|
||||
|
||||
public void setData(@NonNull final String address) {
|
||||
if (address == null) {
|
||||
throw new IllegalArgumentException("Property must not be null: data"); //$NON-NLS-1$
|
||||
}
|
||||
this.data = address;
|
||||
public void setData(@NonNull final String data) {
|
||||
this.data = Preconditions.checkNotNull(data, "data"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Pure
|
||||
|
@ -107,10 +106,7 @@ public class CDTDebugProtocol {
|
|||
}
|
||||
|
||||
public void setAddress(@NonNull final String address) {
|
||||
if (address == null) {
|
||||
throw new IllegalArgumentException("Property must not be null: address"); //$NON-NLS-1$
|
||||
}
|
||||
this.address = address;
|
||||
this.address = Preconditions.checkNotNull(address, "address"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -177,10 +173,7 @@ public class CDTDebugProtocol {
|
|||
}
|
||||
|
||||
public void setAddress(@NonNull final String address) {
|
||||
if (address == null) {
|
||||
throw new IllegalArgumentException("Property must not be null: address"); //$NON-NLS-1$
|
||||
}
|
||||
this.address = address;
|
||||
this.address = Preconditions.checkNotNull(address, "address"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Pure
|
||||
|
@ -190,10 +183,7 @@ public class CDTDebugProtocol {
|
|||
}
|
||||
|
||||
public void setLength(@NonNull final Long length) {
|
||||
if (length == null) {
|
||||
throw new IllegalArgumentException("Property must not be null: length"); //$NON-NLS-1$
|
||||
}
|
||||
this.length = length;
|
||||
this.length = Preconditions.checkNotNull(length, "length"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Pure
|
||||
|
@ -201,11 +191,8 @@ public class CDTDebugProtocol {
|
|||
return this.offset;
|
||||
}
|
||||
|
||||
public void setOffset(@NonNull final Long length) {
|
||||
if (length == null) {
|
||||
throw new IllegalArgumentException("Property must not be null: offset"); //$NON-NLS-1$
|
||||
}
|
||||
this.offset = length;
|
||||
public void setOffset(final Long offset) {
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -256,6 +243,60 @@ public class CDTDebugProtocol {
|
|||
return false;
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
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.dialogs;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.viewer;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) {
|
||||
// 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$
|
||||
return new BigInteger(string.substring(2), 16);
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
<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.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>
|
||||
</locations>
|
||||
<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