mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 22:52:11 +02:00
Bug 542488: Memory view support
Change-Id: I8c3343f0ead46ab203d58f77370dd2dadda550ff
This commit is contained in:
parent
d7b7f10255
commit
bf327ec364
8 changed files with 667 additions and 2 deletions
|
@ -23,7 +23,11 @@ Require-Bundle: org.apache.commons.io,
|
||||||
org.eclipse.lsp4e.debug,
|
org.eclipse.lsp4e.debug,
|
||||||
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,
|
||||||
|
org.eclipse.lsp4j.debug,
|
||||||
|
org.eclipse.lsp4j.jsonrpc.debug,
|
||||||
|
com.google.guava,
|
||||||
|
org.eclipse.xtext.xbase.lib
|
||||||
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
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2019 Kichwa Coders and others.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.debug.dap;
|
||||||
|
|
||||||
|
import org.eclipse.lsp4e.debug.debugmodel.DSPDebugElement;
|
||||||
|
import org.eclipse.lsp4e.debug.debugmodel.DSPDebugTarget;
|
||||||
|
|
||||||
|
public class CDTDebugElement extends DSPDebugElement {
|
||||||
|
public CDTDebugElement(DSPDebugTarget target) {
|
||||||
|
super(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ICDTDebugProtocolServer getDebugProtocolServer() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return (ICDTDebugProtocolServer) super.getDebugProtocolServer();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,261 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2019 Kichwa Coders and others.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.debug.dap;
|
||||||
|
|
||||||
|
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
|
||||||
|
import org.eclipse.xtext.xbase.lib.Pure;
|
||||||
|
import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
|
||||||
|
|
||||||
|
public class CDTDebugProtocol {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://github.com/eclipse-cdt/cdt-gdb-adapter/blob/5d788cbbc6ace142b0930375fcd931b4241eddbb/src/GDBDebugSession.ts#L73
|
||||||
|
* export interface MemoryResponse extends Response {
|
||||||
|
* body: MemoryContents;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
public static class MemoryRequestResponse {
|
||||||
|
@NonNull
|
||||||
|
private MemoryContents body;
|
||||||
|
|
||||||
|
@Pure
|
||||||
|
@NonNull
|
||||||
|
public MemoryContents getBody() {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Pure
|
||||||
|
public String toString() {
|
||||||
|
ToStringBuilder b = new ToStringBuilder(this);
|
||||||
|
b.add("body", this.body); //$NON-NLS-1$
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((body == null) ? 0 : body.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
MemoryRequestResponse other = (MemoryRequestResponse) obj;
|
||||||
|
if (body == null) {
|
||||||
|
if (other.body != null)
|
||||||
|
return false;
|
||||||
|
} else if (!body.equals(other.body))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://github.com/eclipse-cdt/cdt-gdb-adapter/blob/5d788cbbc6ace142b0930375fcd931b4241eddbb/src/GDBDebugSession.ts#L67
|
||||||
|
* export interface MemoryContents {
|
||||||
|
* /\* Hex-encoded string of bytes. *\/
|
||||||
|
* data: string;
|
||||||
|
* address: string;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
public static class MemoryContents {
|
||||||
|
@NonNull
|
||||||
|
private String data;
|
||||||
|
@NonNull
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
@Pure
|
||||||
|
@NonNull
|
||||||
|
public String getData() {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Pure
|
||||||
|
@NonNull
|
||||||
|
public String getAddress() {
|
||||||
|
return this.address;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Pure
|
||||||
|
public String toString() {
|
||||||
|
ToStringBuilder b = new ToStringBuilder(this);
|
||||||
|
b.add("data", this.data); //$NON-NLS-1$
|
||||||
|
b.add("address", this.address); //$NON-NLS-1$
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((address == null) ? 0 : address.hashCode());
|
||||||
|
result = prime * result + ((data == null) ? 0 : data.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
MemoryContents other = (MemoryContents) obj;
|
||||||
|
if (address == null) {
|
||||||
|
if (other.address != null)
|
||||||
|
return false;
|
||||||
|
} else if (!address.equals(other.address))
|
||||||
|
return false;
|
||||||
|
if (data == null) {
|
||||||
|
if (other.data != null)
|
||||||
|
return false;
|
||||||
|
} else if (!data.equals(other.data))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://github.com/eclipse-cdt/cdt-gdb-adapter/blob/5d788cbbc6ace142b0930375fcd931b4241eddbb/src/GDBDebugSession.ts#L58
|
||||||
|
* export interface MemoryRequestArguments {
|
||||||
|
* address: string;
|
||||||
|
* length: number;
|
||||||
|
* offset?: number;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class MemoryRequestArguments {
|
||||||
|
@NonNull
|
||||||
|
private String address;
|
||||||
|
@NonNull
|
||||||
|
private Long length;
|
||||||
|
private Long offset;
|
||||||
|
|
||||||
|
@Pure
|
||||||
|
@NonNull
|
||||||
|
public String getAddress() {
|
||||||
|
return this.address;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Pure
|
||||||
|
@NonNull
|
||||||
|
public Long getLength() {
|
||||||
|
return this.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Pure
|
||||||
|
public Long getOffset() {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Pure
|
||||||
|
public String toString() {
|
||||||
|
ToStringBuilder b = new ToStringBuilder(this);
|
||||||
|
b.add("address", this.address); //$NON-NLS-1$
|
||||||
|
b.add("length", this.length); //$NON-NLS-1$
|
||||||
|
b.add("offset", this.offset); //$NON-NLS-1$
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Pure
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((address == null) ? 0 : address.hashCode());
|
||||||
|
result = prime * result + ((length == null) ? 0 : length.hashCode());
|
||||||
|
result = prime * result + ((offset == null) ? 0 : offset.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Pure
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
MemoryRequestArguments other = (MemoryRequestArguments) obj;
|
||||||
|
if (address == null) {
|
||||||
|
if (other.address != null)
|
||||||
|
return false;
|
||||||
|
} else if (!address.equals(other.address))
|
||||||
|
return false;
|
||||||
|
if (length == null) {
|
||||||
|
if (other.length != null)
|
||||||
|
return false;
|
||||||
|
} else if (!length.equals(other.length))
|
||||||
|
return false;
|
||||||
|
if (offset == null) {
|
||||||
|
if (other.offset != null)
|
||||||
|
return false;
|
||||||
|
} else if (!offset.equals(other.offset))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2019 Kichwa Coders and others.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.debug.dap;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.debug.dap.CDTDebugProtocol.MemoryContents;
|
||||||
|
import org.eclipse.cdt.debug.dap.CDTDebugProtocol.MemoryRequestArguments;
|
||||||
|
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.IMemoryBlock;
|
||||||
|
import org.eclipse.debug.core.model.IMemoryBlockExtension;
|
||||||
|
import org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension;
|
||||||
|
import org.eclipse.lsp4e.debug.debugmodel.DSPDebugTarget;
|
||||||
|
import org.eclipse.lsp4j.debug.services.IDebugProtocolServer;
|
||||||
|
import org.eclipse.lsp4j.jsonrpc.Launcher;
|
||||||
|
import org.eclipse.lsp4j.jsonrpc.MessageConsumer;
|
||||||
|
import org.eclipse.lsp4j.jsonrpc.debug.DebugLauncher;
|
||||||
|
|
||||||
|
public class DapDebugTarget extends DSPDebugTarget implements IMemoryBlockRetrievalExtension, ICDTDebugProtocolClient {
|
||||||
|
|
||||||
|
public DapDebugTarget(ILaunch launch, Runnable processCleanup, InputStream in, OutputStream out,
|
||||||
|
Map<String, Object> dspParameters) {
|
||||||
|
super(launch, processCleanup, in, out, dspParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Launcher<? extends IDebugProtocolServer> createLauncher(UnaryOperator<MessageConsumer> wrapper,
|
||||||
|
InputStream in, OutputStream out, ExecutorService threadPool) {
|
||||||
|
Launcher<ICDTDebugProtocolServer> debugProtocolLauncher = DebugLauncher.createLauncher(this,
|
||||||
|
ICDTDebugProtocolServer.class, in, out, threadPool, wrapper);
|
||||||
|
return debugProtocolLauncher;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ICDTDebugProtocolServer getDebugProtocolServer() {
|
||||||
|
return (ICDTDebugProtocolServer) super.getDebugProtocolServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsStorageRetrieval() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException {
|
||||||
|
throw new DebugException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, DebugException.NOT_SUPPORTED,
|
||||||
|
"getMemoryBlock() not supported, use getExtendedMemoryBlock()", null)); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IMemoryBlockExtension getExtendedMemoryBlock(String expression, Object context) throws DebugException {
|
||||||
|
BigInteger bigBaseAddress;
|
||||||
|
/*
|
||||||
|
* See if the expression is a simple numeric value; if it is, we can
|
||||||
|
* avoid some costly processing (calling the back-end to resolve the
|
||||||
|
* expression and obtain an address)
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
// Now, try to parse the expression. If a NumberFormatException is
|
||||||
|
// thrown, then it wasn't a simple numerical expression and we give
|
||||||
|
// up as debug adapter hasn't provided us what was needed
|
||||||
|
bigBaseAddress = BigInteger.valueOf(Long.decode(expression));
|
||||||
|
|
||||||
|
} catch (NumberFormatException nfexc) {
|
||||||
|
MemoryRequestArguments memoryRequestArguments = new MemoryRequestArguments();
|
||||||
|
memoryRequestArguments.setAddress(expression);
|
||||||
|
memoryRequestArguments.setLength(1L);
|
||||||
|
CompletableFuture<MemoryContents> memory = getDebugProtocolServer().memory(memoryRequestArguments);
|
||||||
|
MemoryContents body = complete(memory);
|
||||||
|
String address = body.getAddress();
|
||||||
|
try {
|
||||||
|
bigBaseAddress = BigInteger.valueOf(Long.decode(address));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// still no resolvable address
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new MemoryBlock(this, expression, bigBaseAddress, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -11,6 +11,7 @@
|
||||||
package org.eclipse.cdt.debug.dap;
|
package org.eclipse.cdt.debug.dap;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -24,10 +25,12 @@ import org.eclipse.core.runtime.FileLocator;
|
||||||
import org.eclipse.core.runtime.IProgressMonitor;
|
import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
import org.eclipse.core.runtime.IStatus;
|
import org.eclipse.core.runtime.IStatus;
|
||||||
import org.eclipse.core.runtime.Status;
|
import org.eclipse.core.runtime.Status;
|
||||||
|
import org.eclipse.core.runtime.SubMonitor;
|
||||||
import org.eclipse.debug.core.DebugPlugin;
|
import org.eclipse.debug.core.DebugPlugin;
|
||||||
import org.eclipse.debug.core.ILaunch;
|
import org.eclipse.debug.core.ILaunch;
|
||||||
import org.eclipse.debug.core.ILaunchConfiguration;
|
import org.eclipse.debug.core.ILaunchConfiguration;
|
||||||
import org.eclipse.debug.core.Launch;
|
import org.eclipse.debug.core.Launch;
|
||||||
|
import org.eclipse.debug.core.model.IDebugTarget;
|
||||||
import org.eclipse.debug.core.model.IPersistableSourceLocator;
|
import org.eclipse.debug.core.model.IPersistableSourceLocator;
|
||||||
import org.eclipse.debug.core.sourcelookup.IPersistableSourceLocator2;
|
import org.eclipse.debug.core.sourcelookup.IPersistableSourceLocator2;
|
||||||
import org.eclipse.jface.dialogs.ErrorDialog;
|
import org.eclipse.jface.dialogs.ErrorDialog;
|
||||||
|
@ -82,7 +85,18 @@ public class DapLaunchDelegate extends AbstractCLaunchDelegate2 {
|
||||||
builder.setMonitorDebugAdapter(true);
|
builder.setMonitorDebugAdapter(true);
|
||||||
builder.setDspParameters(param);
|
builder.setDspParameters(param);
|
||||||
|
|
||||||
new DSPLaunchDelegate().launch(builder);
|
DSPLaunchDelegate dspLaunchDelegate = new DSPLaunchDelegate() {
|
||||||
|
@Override
|
||||||
|
protected IDebugTarget createDebugTarget(SubMonitor subMonitor, Runnable cleanup,
|
||||||
|
InputStream inputStream, java.io.OutputStream outputStream, ILaunch launch,
|
||||||
|
Map<String, Object> dspParameters) throws CoreException {
|
||||||
|
DapDebugTarget target = new DapDebugTarget(launch, cleanup, inputStream, outputStream,
|
||||||
|
dspParameters);
|
||||||
|
target.initialize(subMonitor.split(80));
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
dspLaunchDelegate.launch(builder);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
IStatus errorStatus = new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e);
|
IStatus errorStatus = new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e);
|
||||||
Activator.getDefault().getLog().log(errorStatus);
|
Activator.getDefault().getLog().log(errorStatus);
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2019 Kichwa Coders and others.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.debug.dap;
|
||||||
|
|
||||||
|
import org.eclipse.lsp4j.debug.services.IDebugProtocolClient;
|
||||||
|
|
||||||
|
public interface ICDTDebugProtocolClient extends IDebugProtocolClient {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2019 Kichwa Coders and others.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.debug.dap;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.debug.dap.CDTDebugProtocol.MemoryContents;
|
||||||
|
import org.eclipse.cdt.debug.dap.CDTDebugProtocol.MemoryRequestArguments;
|
||||||
|
import org.eclipse.lsp4j.debug.services.IDebugProtocolServer;
|
||||||
|
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest;
|
||||||
|
|
||||||
|
public interface ICDTDebugProtocolServer extends IDebugProtocolServer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request a memory block
|
||||||
|
*/
|
||||||
|
@JsonRequest(value = "cdt-gdb-adapter/Memory")
|
||||||
|
default CompletableFuture<MemoryContents> memory(MemoryRequestArguments args) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,215 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2019 Kichwa Coders and others.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.debug.dap;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.debug.dap.CDTDebugProtocol.MemoryContents;
|
||||||
|
import org.eclipse.cdt.debug.dap.CDTDebugProtocol.MemoryRequestArguments;
|
||||||
|
import org.eclipse.debug.core.DebugException;
|
||||||
|
import org.eclipse.debug.core.model.IMemoryBlockExtension;
|
||||||
|
import org.eclipse.debug.core.model.IMemoryBlockRetrieval;
|
||||||
|
import org.eclipse.debug.core.model.MemoryByte;
|
||||||
|
|
||||||
|
public class MemoryBlock extends CDTDebugElement implements IMemoryBlockExtension {
|
||||||
|
private ArrayList<Object> connections = new ArrayList<>();
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private boolean isEnabled;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private Object context;
|
||||||
|
|
||||||
|
private DapDebugTarget debugTarget;
|
||||||
|
|
||||||
|
private BigInteger bigBaseAddress;
|
||||||
|
|
||||||
|
private String expression;
|
||||||
|
|
||||||
|
public MemoryBlock(DapDebugTarget debugTarget, String expression, BigInteger bigBaseAddress, Object context) {
|
||||||
|
super(debugTarget);
|
||||||
|
this.debugTarget = debugTarget;
|
||||||
|
this.expression = expression;
|
||||||
|
this.bigBaseAddress = bigBaseAddress;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getStartAddress() {
|
||||||
|
// Not implemented (obsoleted by IMemoryBlockExtension)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLength() {
|
||||||
|
// Not implemented (obsoleted by IMemoryBlockExtension)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getBytes() throws DebugException {
|
||||||
|
// Not implemented (obsoleted by IMemoryBlockExtension)
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsValueModification() {
|
||||||
|
// TODO
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setValue(long offset, byte[] bytes) throws DebugException {
|
||||||
|
// Not implemented (obsoleted by IMemoryBlockExtension)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getExpression() {
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigInteger getBigBaseAddress() throws DebugException {
|
||||||
|
return bigBaseAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigInteger getMemoryBlockStartAddress() throws DebugException {
|
||||||
|
// Null indicates that memory can be retrieved at addresses lower than the block base address
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigInteger getMemoryBlockEndAddress() throws DebugException {
|
||||||
|
// Null indicates that memory can be retrieved at addresses higher the block base address
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigInteger getBigLength() throws DebugException {
|
||||||
|
// -1 indicates that memory block is unbounded
|
||||||
|
return BigInteger.valueOf(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAddressSize() throws DebugException {
|
||||||
|
// TODO Get this from backend
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAddressableSize() throws DebugException {
|
||||||
|
// TODO Get this from backend
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportBaseAddressModification() throws DebugException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsChangeManagement() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBaseAddress(BigInteger address) throws DebugException {
|
||||||
|
// Not supported
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MemoryByte[] getBytesFromOffset(BigInteger offset, long units) throws DebugException {
|
||||||
|
return getBytesFromAddress(getBigBaseAddress().add(offset), units);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MemoryByte[] getBytesFromAddress(BigInteger address, long units) throws DebugException {
|
||||||
|
MemoryRequestArguments memoryRequestArguments = new MemoryRequestArguments();
|
||||||
|
memoryRequestArguments.setAddress("0x" + address.toString(16));
|
||||||
|
memoryRequestArguments.setLength(units);
|
||||||
|
CompletableFuture<MemoryContents> memory = getDebugProtocolServer().memory(memoryRequestArguments);
|
||||||
|
MemoryContents body = complete(memory);
|
||||||
|
String resultAddress = body.getAddress();
|
||||||
|
String contents = body.getData();
|
||||||
|
BigInteger bigResultAddress;
|
||||||
|
BigInteger.valueOf(Long.decode(resultAddress));
|
||||||
|
try {
|
||||||
|
bigResultAddress = BigInteger.valueOf(Long.decode(resultAddress));
|
||||||
|
} catch (NumberFormatException nfexc) {
|
||||||
|
// TODO
|
||||||
|
bigResultAddress = address;
|
||||||
|
}
|
||||||
|
int numRequestedBytes = (int) (units * getAddressableSize());
|
||||||
|
MemoryByte[] bytes = new MemoryByte[numRequestedBytes];
|
||||||
|
int resultOffsetFromRequest = bigResultAddress.subtract(address).intValue();
|
||||||
|
|
||||||
|
for (int i = 0; i < resultOffsetFromRequest; i++) {
|
||||||
|
bytes[i] = new MemoryByte((byte) 0, (byte) (0 & ~MemoryByte.READABLE));
|
||||||
|
}
|
||||||
|
for (int i = resultOffsetFromRequest, k = 0; i < resultOffsetFromRequest + (contents.length() / 2)
|
||||||
|
&& i < numRequestedBytes; i++, k += 2) {
|
||||||
|
byte b = (byte) Integer.parseInt(contents.substring(k, k + 2), 16);
|
||||||
|
bytes[i] = new MemoryByte(b);
|
||||||
|
}
|
||||||
|
for (int i = resultOffsetFromRequest + (contents.length() / 2); i < numRequestedBytes; i++) {
|
||||||
|
bytes[i] = new MemoryByte((byte) 0, (byte) (0 & ~MemoryByte.READABLE));
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setValue(BigInteger offset, byte[] bytes) throws DebugException {
|
||||||
|
// Not supported
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() throws DebugException {
|
||||||
|
// nothing to do yet
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IMemoryBlockRetrieval getMemoryBlockRetrieval() {
|
||||||
|
return debugTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connect(Object client) {
|
||||||
|
if (!connections.contains(client))
|
||||||
|
connections.add(client);
|
||||||
|
if (connections.size() == 1)
|
||||||
|
enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnect(Object client) {
|
||||||
|
if (connections.contains(client))
|
||||||
|
connections.remove(client);
|
||||||
|
if (connections.size() == 0)
|
||||||
|
disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getConnections() {
|
||||||
|
return connections.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enable() {
|
||||||
|
isEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disable() {
|
||||||
|
isEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue