You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by en...@apache.org on 2021/04/01 21:35:18 UTC
[netbeans] 02/03: Native debugging of GraalVM's native images.
This is an automated email from the ASF dual-hosted git repository.
entl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git
commit 0344bcf958a48aff2f941738a0f7711bb5d2f3f9
Author: Martin Entlicher <ma...@oracle.com>
AuthorDate: Mon Mar 22 16:44:49 2021 +0100
Native debugging of GraalVM's native images.
---
cpplite/cpplite.debugger/nbproject/project.xml | 18 +
.../modules/cpplite/debugger/CPPFrame.java | 247 +++++++--
.../modules/cpplite/debugger/CPPLiteDebugger.java | 150 ++++--
.../cpplite/debugger/CPPLiteDebuggerConfig.java | 10 +-
.../modules/cpplite/debugger/CPPThread.java | 11 +-
.../modules/cpplite/debugger/CPPVariable.java | 61 ++-
.../debugger/DebuggerBreakpointAnnotation.java | 14 +-
.../modules/cpplite/debugger/ThreadsCollector.java | 2 +-
.../cpplite/debugger/ToolTipAnnotation.java | 11 +-
.../modules/cpplite/debugger/api/Debugger.java | 6 +-
.../breakpoints/BreakpointAnnotationProvider.java | 13 +-
.../debugger/breakpoints/BreakpointModel.java | 15 +-
.../debugger/breakpoints/BreakpointsReader.java | 89 ++-
.../debugger/breakpoints/CPPLiteBreakpoint.java | 135 ++++-
.../CPPLiteBreakpointActionProvider.java | 33 +-
.../debugger/breakpoints/PersistenceManager.java | 13 +-
.../debugger/debuggingview/DebuggingModel.java | 4 +-
.../cpplite/debugger/models/CallStackModel.java | 27 +-
.../cpplite/debugger/models/VariablesModel.java | 52 +-
.../cpplite/debugger/models/WatchesModel.java | 27 +-
.../modules/cpplite/debugger/ni/NIBreakpoints.java | 85 +++
.../debugger/ni/NIDebuggerProviderImpl.java | 172 ++++++
.../NIDebuggerServiceProviderImpl.java} | 25 +-
.../cpplite/debugger/AbstractDebugTest.java | 3 +-
.../modules/cpplite/debugger/BreakpointsTest.java | 8 +-
.../modules/cpplite/debugger/StepTest.java | 2 +-
.../cpplite/project/ActionProviderImpl.java | 2 +-
ide/ide.kit/nbproject/project.xml | 7 +
ide/nativeimage.api/build.xml | 28 +
ide/nativeimage.api/manifest.mf | 6 +
ide/nativeimage.api/nbproject/project.properties | 19 +
.../nativeimage.api}/nbproject/project.xml | 100 +---
.../modules/nativeimage/api/Bundle.properties | 20 +
.../nativeimage/api/debug}/EvaluateException.java | 24 +-
.../modules/nativeimage/api/debug/NIDebugger.java | 211 ++++++++
.../modules/nativeimage/api/debug/NIFrame.java | 69 +++
.../api/debug/NILineBreakpointDescriptor.java | 179 +++++++
.../modules/nativeimage/api/debug/NIVariable.java | 96 ++++
.../nativeimage/spi/debug/NIDebuggerProvider.java | 123 +++++
.../spi/debug/NIDebuggerServiceProvider.java | 18 +-
.../spi/debug/filters/FrameDisplayer.java | 166 ++++++
.../spi/debug/filters/VariableDisplayer.java | 23 +-
.../nativeimage/debug/NIDebuggerServiceTest.java | 67 +++
.../nativeimage/debug/TestNIDebuggerProvider.java | 103 ++++
.../debug/TestNIDebuggerServiceProvider.java | 25 +-
java/java.kit/nbproject/project.xml | 7 +
.../nbcode/nbproject/platform.properties | 8 +-
java/java.lsp.server/nbproject/project.xml | 18 +
java/java.lsp.server/script/etc/nbcode.clusters | 1 +
.../lsp/server/debugging/NbProtocolServer.java | 115 ++--
.../java/lsp/server/debugging/NbThreads.java | 21 +-
.../server/debugging/launch/NbDebugSession.java | 27 +-
.../server/debugging/launch/NbLaunchDelegate.java | 219 +++++---
.../debugging/launch/NbLaunchRequestHandler.java | 64 ++-
.../variables/NbVariablesRequestHandler.java | 23 +-
java/java.lsp.server/vscode/package.json | 55 ++
java/java.lsp.server/vscode/src/extension.ts | 26 +
java/java.nativeimage.debugger/build.xml | 28 +
java/java.nativeimage.debugger/manifest.mf | 7 +
.../nbproject/project.properties | 19 +
.../nbproject/project.xml | 88 +--
.../java/nativeimage/debugger/Bundle.properties | 20 +
.../nativeimage/debugger/actions/Bundle.properties | 21 +
.../debugger/actions/NIAttachCustomizer.form | 125 +++++
.../debugger/actions/NIAttachCustomizer.java | 378 +++++++++++++
.../nativeimage/debugger/actions/NIAttachType.java | 56 ++
.../nativeimage/debugger/api/NIDebugRunner.java | 90 ++++
.../breakpoints/JPDABreakpointsHandler.java | 183 +++++++
.../debugger/displayer/JavaFrameDisplayer.java | 206 +++++++
.../debugger/displayer/JavaVariablesDisplayer.java | 596 +++++++++++++++++++++
.../nativeimage/debugger/resources/mf-layer.xml | 32 ++
.../nativeimage/debugger/NIDebugRunnerTest.java | 78 +++
.../debugger/TestNIDebuggerProvider.java | 122 +++++
.../debugger/TestNIDebuggerServiceProvider.java | 18 +-
.../java/nativeimage/debugger/TestNIVariable.java | 71 +--
nbbuild/build.properties | 1 +
nbbuild/cluster.properties | 2 +
nbbuild/javadoctools/links.xml | 1 +
nbbuild/javadoctools/properties.xml | 1 +
nbbuild/javadoctools/replaces.xml | 1 +
80 files changed, 4624 insertions(+), 623 deletions(-)
diff --git a/cpplite/cpplite.debugger/nbproject/project.xml b/cpplite/cpplite.debugger/nbproject/project.xml
index d360c06..48ff741 100644
--- a/cpplite/cpplite.debugger/nbproject/project.xml
+++ b/cpplite/cpplite.debugger/nbproject/project.xml
@@ -52,6 +52,24 @@
</run-dependency>
</dependency>
<dependency>
+ <code-name-base>org.netbeans.modules.extexecution</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>2</release-version>
+ <specification-version>1.59</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.netbeans.modules.nativeimage.api</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>0</release-version>
+ <specification-version>0.1</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
<code-name-base>org.netbeans.modules.projectapi</code-name-base>
<build-prerequisite/>
<compile-dependency/>
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPFrame.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPFrame.java
index 3e5fd4c..c7315f5 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPFrame.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPFrame.java
@@ -19,14 +19,16 @@
package org.netbeans.modules.cpplite.debugger;
import java.io.File;
+import java.net.MalformedURLException;
import java.net.URI;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
-import java.util.function.Consumer;
+import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
+
import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.modules.cnd.debugger.gdb2.mi.MIConst;
import org.netbeans.modules.cnd.debugger.gdb2.mi.MIRecord;
@@ -34,10 +36,17 @@ import org.netbeans.modules.cnd.debugger.gdb2.mi.MIResult;
import org.netbeans.modules.cnd.debugger.gdb2.mi.MITList;
import org.netbeans.modules.cnd.debugger.gdb2.mi.MITListItem;
import org.netbeans.modules.cnd.debugger.gdb2.mi.MIValue;
+import org.netbeans.modules.nativeimage.api.debug.EvaluateException;
+import org.netbeans.modules.nativeimage.api.debug.NIFrame;
+import org.netbeans.modules.nativeimage.api.debug.NIVariable;
+import org.netbeans.modules.nativeimage.spi.debug.filters.FrameDisplayer;
+import org.netbeans.modules.nativeimage.spi.debug.filters.FrameDisplayer.DisplayedFrame;
import org.netbeans.spi.debugger.ui.DebuggingView.DVFrame;
+
import org.openide.cookies.LineCookie;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
+import org.openide.filesystems.URLMapper;
import org.openide.text.Line;
import org.openide.util.Pair;
@@ -46,47 +55,62 @@ public final class CPPFrame implements DVFrame {
private static final Logger LOGGER = Logger.getLogger(CPPFrame.class.getName());
private final CPPThread thread;
- private final String address;
- public final String shortFileName;
- public final String fullFileName;
- public final String functionName;
- public final int line;
+ private final DisplayedFrame displayedFrame;
+ private final NIFrame niFrame;
public final int level;
- private volatile Map<String, CPPVariable> variables;
+ private volatile Map<String, NIVariable> variables;
- CPPFrame(CPPThread thread, MITList frame) {
+ private CPPFrame(CPPThread thread, DisplayedFrame displayedFrame, NIFrame niFrame) {
Objects.requireNonNull(thread);
+ Objects.requireNonNull(displayedFrame);
+ Objects.requireNonNull(niFrame);
this.thread = thread;
- this.address = frame.getConstValue("addr");
- this.shortFileName = frame.valueOf("file") != null ? frame.valueOf("file").asConst().value() : null;
- this.functionName = frame.valueOf("func").asConst().value();
- this.fullFileName = frame.valueOf("fullname") != null ? frame.valueOf("fullname").asConst().value() : null;
- this.line = frame.valueOf("line") != null ? Integer.parseInt(frame.valueOf("line").asConst().value()) : 1;
- if (frame.valueOf("level") != null) {
- this.level = Integer.parseInt(frame.valueOf("level").asConst().value());
- } else {
- this.level = 0;
+ this.displayedFrame = displayedFrame;
+ this.niFrame = niFrame;
+ this.level = niFrame.getLevel();
+ }
+
+ static CPPFrame create(CPPThread thread, MITList frame) {
+ NIFrame niFrame = new NIFrameImpl(thread.getId(), frame);
+ FrameDisplayer frameDisplayer = thread.getDebugger().getContextProvider().lookupFirst(null, FrameDisplayer.class);
+ DisplayedFrame displayedFrame = frameDisplayer != null ? frameDisplayer.displayed(niFrame) : createDisplayedFrame(niFrame);
+ if (displayedFrame == null) {
+ return null; // Not to be displayed
}
+ return new CPPFrame(thread, displayedFrame, niFrame);
}
- String getAddress() {
- return address;
+ NIFrame getFrame() {
+ return niFrame;
}
@Override
public String getName() {
- return functionName;
+ return displayedFrame.getDisplayName();
+ }
+
+ public String getDescription() {
+ return displayedFrame.getDescription();
}
@CheckForNull
public Line location() {
- FileObject file = FileUtil.toFileObject(FileUtil.normalizeFile(new File(fullFileName)));
+ URI sourceURI = displayedFrame.getSourceURI();
+ if (sourceURI == null) {
+ return null;
+ }
+ FileObject file;
+ try {
+ file = URLMapper.findFileObject(sourceURI.toURL());
+ } catch (MalformedURLException ex) {
+ return null;
+ }
if (file == null) {
return null;
}
LineCookie lc = file.getLookup().lookup(LineCookie.class);
- return lc.getLineSet().getOriginal(line - 1);
+ return lc.getLineSet().getOriginal(displayedFrame.getLine() - 1);
}
@Override
@@ -101,17 +125,12 @@ public final class CPPFrame implements DVFrame {
@Override
public URI getSourceURI() {
- FileObject file = FileUtil.toFileObject(FileUtil.normalizeFile(new File(fullFileName)));
- if (file != null) {
- return file.toURI();
- } else {
- return null;
- }
+ return displayedFrame.getSourceURI();
}
@Override
public int getLine() {
- return line;
+ return displayedFrame.getLine();
}
@Override
@@ -119,8 +138,8 @@ public final class CPPFrame implements DVFrame {
return -1;
}
- public Map<String, CPPVariable> getVariables() {
- Map<String, CPPVariable> vars = variables;
+ public Map<String, NIVariable> getVariables() {
+ Map<String, NIVariable> vars = variables;
if (vars == null) {
synchronized (this) {
vars = variables;
@@ -132,12 +151,13 @@ public final class CPPFrame implements DVFrame {
return vars;
}
- static Map<String, CPPVariable> retrieveVariables(CPPFrame frame, CPPVariable parentVar) {
+ static Map<String, NIVariable> retrieveVariables(CPPFrame frame, CPPVariable parentVar) {
MIRecord record;
try {
if (parentVar == null) {
record = frame.thread.getDebugger().sendAndGet("-stack-list-variables --thread " + frame.thread.getId() + " --frame " + frame.level + " --no-frame-filters 2");
} else {
+ // from to
record = frame.thread.getDebugger().sendAndGet("-var-list-children --thread " + frame.thread.getId() + " --frame " + frame.level + " --all-values " + parentVar.getUniqueName());
}
} catch (InterruptedException ex) {
@@ -150,7 +170,7 @@ public final class CPPFrame implements DVFrame {
if (results.isEmpty()) {
return Collections.emptyMap();
}
- Map<String, CPPVariable> map = new LinkedHashMap<>(results.size());
+ Map<String, NIVariable> map = new LinkedHashMap<>(results.size());
MIValue children = results.valueOf("children");
if (children != null) {
for (MITListItem item : children.asList()) {
@@ -160,11 +180,13 @@ public final class CPPFrame implements DVFrame {
int numChildren = Integer.parseInt(child.getConstValue("numchild"));
String type = child.getConstValue("type");
MIValue value = child.valueOf("value");
- map.put(name, new CPPVariable(frame, uniqueName, name, type, value, numChildren));
+ map.put(name, new CPPVariable(frame, parentVar, uniqueName, name, type, value, numChildren));
}
} else {
MIValue resultValue = results.valueOf("variables");
- if (resultValue.isConst()) {
+ if (resultValue == null) {
+ return Collections.emptyMap();
+ } else if (resultValue.isConst()) {
return Collections.singletonMap(((MIConst) resultValue).value(), null);
}
results = (MITList) resultValue;
@@ -176,9 +198,11 @@ public final class CPPFrame implements DVFrame {
MIValue value = varList.valueOf("value");
Pair<String, Integer> uniqueVar = createVariable(frame, name);
String uniqueName = uniqueVar.first();
- int numChildren = uniqueVar.second();
- LOGGER.log(Level.FINE, " {0} = ({1}) {2} ; [{3}]", new Object[]{name, type, value, numChildren});
- map.put(name, new CPPVariable(frame, uniqueName, name, type, value, numChildren));
+ if (uniqueName != null) {
+ int numChildren = uniqueVar.second();
+ LOGGER.log(Level.FINE, " {0} = ({1}) {2} ; [{3}]", new Object[]{name, type, value, numChildren});
+ map.put(name, new CPPVariable(frame, parentVar, uniqueName, name, type, value, numChildren));
+ }
}
}
return map;
@@ -191,9 +215,12 @@ public final class CPPFrame implements DVFrame {
try {
record = frame.thread.getDebugger().sendAndGet("-var-create --thread " + frame.thread.getId() + " --frame " + frame.level + " - " + "*" + " " + variableName);
if (!record.isError() && !record.isEmpty()) {
- uniqueName = record.results().getConstValue("name");
- String numchild = record.results().getConstValue("numchild");
- numChildren = Integer.parseInt(numchild);
+ String name = record.results().getConstValue("name");
+ if (!name.isEmpty()) {
+ uniqueName = name;
+ String numchild = record.results().getConstValue("numchild");
+ numChildren = Integer.parseInt(numchild);
+ }
}
} catch (InterruptedException ex) {
}
@@ -216,13 +243,21 @@ public final class CPPFrame implements DVFrame {
return numChildren;
}
- public void evaluateLazy(String expression, Consumer<CPPVariable> result, Consumer<EvaluateException> exception) {
- CPPVariable value = getVariables().get(expression);
+ private static final String MI_ERROR = "MI parse error: ";
+
+ public CompletableFuture<NIVariable> evaluateAsync(String expression) {
+ return evaluateAsync(expression, null);
+ }
+
+ public CompletableFuture<NIVariable> evaluateAsync(String expression, String resultName) {
+ String resultVarName = (resultName != null) ? resultName : expression;
+ CompletableFuture<NIVariable> result = new CompletableFuture<>();
+ NIVariable value = getVariables().get(expression);
if (value != null) {
- result.accept(value);
- return;
+ result.complete(value);
+ return result;
}
- thread.getDebugger().send(new Command("-var-create - * " + expression) {
+ thread.getDebugger().send(new Command("-var-create --thread " + thread.getId() + " --frame " + level + " - * " + expression) {
@Override
protected void onDone(MIRecord record) {
MITList results = record.results();
@@ -237,14 +272,128 @@ public final class CPPFrame implements DVFrame {
} else {
numChildren = retrieveNumChildren(CPPFrame.this, varName);
}
- result.accept(new CPPVariable(CPPFrame.this, expression, expression, type, resultValue, numChildren));
- thread.getDebugger().send(new Command("-var-delete " + varName));
+ result.complete(new CPPVariable(CPPFrame.this, null, varName, resultVarName, type, resultValue, numChildren));
+ //thread.getDebugger().send(new Command("-var-delete " + varName));
}
@Override
protected void onError(MIRecord record) {
- exception.accept(new EvaluateException(record.error()));
+ String error = record.error();
+ if (error.startsWith(MI_ERROR)) {
+ error = error.substring(MI_ERROR.length());
+ result.completeExceptionally(new EvaluateException(error));
+ }
}
});
+ return result;
+ }
+
+ private static DisplayedFrame createDisplayedFrame(NIFrame frame) {
+ return DisplayedFrame.newBuilder(getDisplayName(frame))
+ .description(getDescription(frame))
+ .line(frame.getLine())
+ .sourceURISupplier(() -> getSourceURI(frame))
+ .build();
+ }
+
+ private static String getDisplayName(NIFrame frame) {
+ StringBuilder builder = new StringBuilder(frame.getFunctionName());
+ String shortName = frame.getShortFileName();
+ if (shortName != null) {
+ builder.append("; ");
+ builder.append(shortName);
+ }
+ int line = frame.getLine();
+ if (line > 0) {
+ builder.append(':');
+ builder.append(line);
+ }
+ return builder.toString();
+ }
+
+ private static String getDescription(NIFrame frame) {
+ StringBuilder builder = new StringBuilder(frame.getFunctionName());
+ String fullName = frame.getFullFileName();
+ if (fullName != null) {
+ builder.append("; ");
+ builder.append(fullName);
+ }
+ int line = frame.getLine();
+ if (line > 0) {
+ builder.append(':');
+ builder.append(line);
+ }
+ return builder.toString();
+ }
+ private static URI getSourceURI(NIFrame frame) {
+ String fullFileName = frame.getFullFileName();
+ if (fullFileName != null && !fullFileName.isEmpty()) {
+ FileObject file = FileUtil.toFileObject(FileUtil.normalizeFile(new File(fullFileName)));
+ if (file != null) {
+ return file.toURI();
+ }
+ }
+ return null;
}
+
+ private static final class NIFrameImpl implements NIFrame {
+
+ private final String threadId;
+ private final int level;
+ private final String address;
+ private final String shortFileName;
+ private final String fullFileName;
+ private final String functionName;
+ private final int line;
+
+ NIFrameImpl(String threadId, MITList frame) {
+ this.threadId = threadId;
+ this.address = frame.getConstValue("addr");
+ this.shortFileName = frame.valueOf("file") != null ? frame.valueOf("file").asConst().value() : null;
+ this.functionName = frame.valueOf("func").asConst().value();
+ this.fullFileName = frame.valueOf("fullname") != null ? frame.valueOf("fullname").asConst().value() : null;
+ this.line = frame.valueOf("line") != null ? Integer.parseInt(frame.valueOf("line").asConst().value()) : -1;
+ if (frame.valueOf("level") != null) {
+ this.level = Integer.parseInt(frame.valueOf("level").asConst().value());
+ } else {
+ this.level = 0;
+ }
+ }
+
+ @Override
+ public String getAddress() {
+ return address;
+ }
+
+ @Override
+ public String getShortFileName() {
+ return shortFileName;
+ }
+
+ @Override
+ public String getFullFileName() {
+ return fullFileName;
+ }
+
+ @Override
+ public String getFunctionName() {
+ return functionName;
+ }
+
+ @Override
+ public int getLine() {
+ return line;
+ }
+
+ @Override
+ public String getThreadId() {
+ return threadId;
+ }
+
+ @Override
+ public int getLevel() {
+ return level;
+ }
+ }
+
}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteDebugger.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteDebugger.java
index 87d6587..6ca0f17 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteDebugger.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteDebugger.java
@@ -28,6 +28,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.EventListener;
import java.util.List;
import java.util.Map;
@@ -51,6 +52,7 @@ import org.netbeans.modules.cnd.debugger.gdb2.mi.MIConst;
import org.netbeans.modules.cnd.debugger.gdb2.mi.MIProxy;
import org.netbeans.modules.cnd.debugger.gdb2.mi.MIRecord;
import org.netbeans.modules.cnd.debugger.gdb2.mi.MITList;
+import org.netbeans.modules.cnd.debugger.gdb2.mi.MITListItem;
import org.netbeans.modules.cnd.debugger.gdb2.mi.MIValue;
import org.netbeans.modules.cpplite.debugger.breakpoints.CPPLiteBreakpoint;
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironmentFactory;
@@ -125,6 +127,10 @@ public final class CPPLiteDebugger {
proxy.send(new Command("-gdb-set target-async"));
//proxy.send(new Command("-gdb-set scheduler-locking on"));
proxy.send(new Command("-gdb-set non-stop on"));
+ proxy.send(new Command("-gdb-set print object on"));
+ }
+
+ public void execRun() {
proxy.send(new Command("-exec-run"));
}
@@ -365,6 +371,46 @@ public final class CPPLiteDebugger {
LOGGER.fine("finish() done, build finished.");
}
+ public String readMemory(String address, long offset, int length) {
+ MIRecord memory;
+ String offsetArg;
+ if (offset != 0) {
+ offsetArg = "-o " + offset + " ";
+ } else {
+ offsetArg = "";
+ }
+ try {
+ memory = sendAndGet("-data-read-memory-bytes " + offsetArg + address + " " + length);
+ } catch (InterruptedException ex) {
+ return null;
+ }
+ MIValue memoryValue = memory.results().valueOf("memory");
+ if (memoryValue instanceof MITList) {
+ MITList memoryList = (MITList) memoryValue;
+ if (!memoryList.isEmpty()) {
+ MITListItem row = memoryList.get(0);
+ if (row instanceof MITList) {
+ String contents = ((MITList) row).getConstValue("contents");
+ return contents;
+ }
+ }
+ }
+ return null;
+ }
+
+ public String getVersion() {
+ MIRecord versionRecord;
+ try {
+ versionRecord = sendAndGet("-gdb-version");
+ } catch (InterruptedException ex) {
+ return null;
+ }
+ return versionRecord.results().toString();
+ }
+
+ ContextProvider getContextProvider() {
+ return contextProvider;
+ }
DebuggingView.DVSupport getDVSupport() {
return contextProvider.lookupFirst(null, DebuggingView.DVSupport.class);
@@ -421,7 +467,7 @@ public final class CPPLiteDebugger {
break;
default:
MITList topFrameList = (MITList) results.valueOf("frame");
- CPPFrame frame = topFrameList != null ? new CPPFrame(thread, topFrameList) : null;
+ CPPFrame frame = topFrameList != null ? CPPFrame.create(thread, topFrameList) : null;
thread.setTopFrame(frame);
setSuspended(true, thread, frame);
if (frame != null) {
@@ -497,8 +543,16 @@ public final class CPPLiteDebugger {
void send(MICommand cmd, boolean waitForRunning) {
if (waitForRunning) {
waitRunning();
+ send(cmd);
+ } else {
+ try {
+ startedLatch.await();
+ } catch (InterruptedException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ LOGGER.log(Level.FINE, "MIProxy.send({0})", cmd);
+ super.send(cmd);
}
- send(cmd);
}
@Override
@@ -548,40 +602,41 @@ public final class CPPLiteDebugger {
}
- public static @NonNull Pair<DebuggerEngine, Process> startDebugging (CPPLiteDebuggerConfig configuration) throws IOException {
- DebuggerInfo di = DebuggerInfo.create (
- "CPPLiteDebuggerInfo",
- new Object[] {
- new SessionProvider () {
- @Override
- public String getSessionName () {
- return configuration.getDisplayName ();
- }
-
- @Override
- public String getLocationName () {
- return "localhost";
- }
+ public static @NonNull Pair<DebuggerEngine, Process> startDebugging (CPPLiteDebuggerConfig configuration, Object... services) throws IOException {
+ SessionProvider sessionProvider = new SessionProvider () {
+ @Override
+ public String getSessionName () {
+ return configuration.getDisplayName ();
+ }
- @Override
- public String getTypeID () {
- return "CPPLiteSession";
- }
+ @Override
+ public String getLocationName () {
+ return "localhost";
+ }
- @Override
- public Object[] getServices () {
- return new Object[] {};
- }
- },
- configuration
+ @Override
+ public String getTypeID () {
+ return "CPPLiteSession";
}
+
+ @Override
+ public Object[] getServices () {
+ return new Object[] {};
+ }
+ };
+ Object[] allServices = Arrays.copyOf(services, services.length + 2);
+ allServices[services.length] = sessionProvider;
+ allServices[services.length + 1] = configuration;
+ DebuggerInfo di = DebuggerInfo.create(
+ "CPPLiteDebuggerInfo",
+ allServices
);
DebuggerEngine[] es = DebuggerManager.getDebuggerManager ().
startDebugging (di);
Pty pty = PtySupport.allocate(ExecutionEnvironmentFactory.getLocal());
CPPLiteDebugger debugger = es[0].lookupFirst(null, CPPLiteDebugger.class);
List<String> executable = new ArrayList<>();
- executable.add("gdb");
+ executable.add(configuration.getDebugger());
executable.add("--interpreter=mi");
executable.add("--tty=" + pty.getSlaveName());
executable.addAll(configuration.getExecutable());
@@ -700,30 +755,27 @@ public final class CPPLiteDebugger {
}
private void addBreakpoint(CPPLiteBreakpoint breakpoint) {
- Line l = breakpoint.getLine();
- FileObject source = l.getLookup().lookup(FileObject.class);
- File sourceFile = source != null ? FileUtil.toFile(source) : null;
- if (sourceFile != null) {
- String disabled = breakpoint.isEnabled() ? "" : "-d ";
- Command command = new Command("-break-insert " + disabled + sourceFile.getAbsolutePath() + ":" + (l.getLineNumber() + 1)) {
- @Override
- protected void onDone(MIRecord record) {
- MIValue bkpt = record.results().valueOf("bkpt");
- if (bkpt instanceof MITList) {
- breakpointResolved(breakpoint, (MITList) bkpt);
- }
- super.onDone(record);
+ String path = breakpoint.getFilePath();
+ int lineNumber = breakpoint.getLineNumber();
+ String disabled = breakpoint.isEnabled() ? "" : "-d ";
+ Command command = new Command("-break-insert " + disabled + path + ":" + lineNumber) {
+ @Override
+ protected void onDone(MIRecord record) {
+ MIValue bkpt = record.results().valueOf("bkpt");
+ if (bkpt instanceof MITList) {
+ breakpointResolved(breakpoint, (MITList) bkpt);
}
+ super.onDone(record);
+ }
- @Override
- protected void onError(MIRecord record) {
- String msg = record.results().getConstValue("msg");
- breakpointError(breakpoint, msg);
- super.onError(record);
- }
- };
- proxy.send(command);
- }
+ @Override
+ protected void onError(MIRecord record) {
+ String msg = record.results().getConstValue("msg");
+ breakpointError(breakpoint, msg);
+ super.onError(record);
+ }
+ };
+ proxy.send(command, false);
breakpoint.addPropertyChangeListener(this);
}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteDebuggerConfig.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteDebuggerConfig.java
index f88b745..d604d12 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteDebuggerConfig.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteDebuggerConfig.java
@@ -26,14 +26,16 @@ import java.util.List;
*
* @author lahvac
*/
-public class CPPLiteDebuggerConfig {
+public final class CPPLiteDebuggerConfig {
private final List<String> executable;
private final File directory;
+ private final String debugger;
- public CPPLiteDebuggerConfig(List<String> executable, File directory) {
+ public CPPLiteDebuggerConfig(List<String> executable, File directory, String debugger) {
this.executable = executable;
this.directory = directory;
+ this.debugger = debugger;
}
public String getDisplayName() {
@@ -47,4 +49,8 @@ public class CPPLiteDebuggerConfig {
public File getDirectory() {
return directory;
}
+
+ public String getDebugger() {
+ return debugger;
+ }
}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPThread.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPThread.java
index 6158f6e..cfaa991 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPThread.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPThread.java
@@ -21,6 +21,7 @@ package org.netbeans.modules.cpplite.debugger;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.AbstractList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -230,8 +231,14 @@ public final class CPPThread implements DVThread {
stack[0] = topFrame;
i++;
}
- for (; i < l; i++) {
- stack[i] = new CPPFrame(this, (MITList) ((MIResult) stackList.get(i)).value());
+ for (int li = i; li < l; li++) {
+ CPPFrame frame = CPPFrame.create(this, (MITList) ((MIResult) stackList.get(li)).value());
+ if (frame != null) {
+ stack[i++] = frame;
+ }
+ }
+ if (i < l) {
+ stack = Arrays.copyOf(stack, i);
}
this.stack = stack;
}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPVariable.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPVariable.java
index cd5c6fe..ec1ef37 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPVariable.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPVariable.java
@@ -18,27 +18,33 @@
*/
package org.netbeans.modules.cpplite.debugger;
+import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import org.netbeans.modules.cnd.debugger.gdb2.mi.MIConst;
+import org.netbeans.modules.cnd.debugger.gdb2.mi.MIRecord;
import org.netbeans.modules.cnd.debugger.gdb2.mi.MIValue;
+import org.netbeans.modules.nativeimage.api.debug.NIFrame;
+import org.netbeans.modules.nativeimage.api.debug.NIVariable;
/**
* Representation of a variable.
*/
-public final class CPPVariable {
+public final class CPPVariable implements NIVariable {
private final CPPFrame frame;
+ private final CPPVariable parentVariable;
private final String uniqueName;
private final String name;
private final String type;
private final String value;
private final int numChildren;
- private volatile Map<String, CPPVariable> children;
+ private volatile Map<String, NIVariable> children;
- CPPVariable(CPPFrame frame, String uniqueName, String name, String type, MIValue value, int numChildren) {
+ CPPVariable(CPPFrame frame, CPPVariable parentVariable, String uniqueName, String name, String type, MIValue value, int numChildren) {
this.frame = frame;
+ this.parentVariable = parentVariable;
this.uniqueName = uniqueName;
this.name = name;
this.type = type;
@@ -46,28 +52,42 @@ public final class CPPVariable {
this.numChildren = numChildren;
}
+ @Override
+ public NIFrame getFrame() {
+ return frame.getFrame();
+ }
+
+ @Override
+ public CPPVariable getParent() {
+ return parentVariable;
+ }
+
public String getUniqueName() {
return uniqueName;
}
+ @Override
public String getName() {
return name;
}
+ @Override
public String getType() {
return type;
}
+ @Override
public String getValue() {
return value;
}
+ @Override
public int getNumChildren() {
return numChildren;
}
- public Map<String, CPPVariable> getChildrenVariables() {
- Map<String, CPPVariable> vars = children;
+ public Map<String, NIVariable> getChildrenByNames() {
+ Map<String, NIVariable> vars = children;
if (vars == null) {
synchronized (this) {
vars = children;
@@ -78,4 +98,35 @@ public final class CPPVariable {
}
return vars;
}
+
+ @Override
+ public NIVariable[] getChildren(int from, int to) {
+ Map<String, NIVariable> childrenVariables = getChildrenByNames();
+ NIVariable[] array = childrenVariables.values().toArray(new NIVariable[0]);
+ if (array.length == 1 && array[0] == null) {
+ return new NIVariable[0]; // Error
+ }
+ if (from >= 0) {
+ to = Math.min(to, array.length);
+ if (from < to) {
+ array = Arrays.copyOfRange(array, from, to);
+ } else {
+ array = new NIVariable[0];
+ }
+ }
+ return array;
+ }
+
+ @Override
+ public String getExpressionPath() {
+ MIRecord pathRecord;
+ try {
+ pathRecord = frame.getThread().getDebugger().sendAndGet("-var-info-path-expression " + uniqueName);
+ } catch (InterruptedException ex) {
+ return null;
+ }
+ String pathExpression = pathRecord.results().getConstValue("path_expr");
+ return pathExpression;
+ }
+
}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/DebuggerBreakpointAnnotation.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/DebuggerBreakpointAnnotation.java
index f5e90b3..a169105 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/DebuggerBreakpointAnnotation.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/DebuggerBreakpointAnnotation.java
@@ -21,12 +21,14 @@ package org.netbeans.modules.cpplite.debugger;
import java.util.LinkedList;
import java.util.List;
+import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.debugger.Breakpoint;
import org.netbeans.api.debugger.Breakpoint.HIT_COUNT_FILTERING_STYLE;
import org.netbeans.modules.cpplite.debugger.breakpoints.CPPLiteBreakpoint;
import org.netbeans.spi.debugger.ui.BreakpointAnnotation;
import org.openide.text.Annotatable;
+import org.openide.text.Line;
import org.openide.util.NbBundle;
@@ -49,13 +51,21 @@ public class DebuggerBreakpointAnnotation extends BreakpointAnnotation {
private final String type;
private final CPPLiteBreakpoint breakpoint;
- public DebuggerBreakpointAnnotation (String type, CPPLiteBreakpoint b) {
+ private DebuggerBreakpointAnnotation (String type, Annotatable annotatable, CPPLiteBreakpoint b) {
this.type = type;
this.breakpoint = b;
- Annotatable annotatable = b.getLine ();
attach (annotatable);
}
+ @CheckForNull
+ public static DebuggerBreakpointAnnotation create(String type, CPPLiteBreakpoint b) {
+ Line line = b.getLine();
+ if (line == null) {
+ return null;
+ }
+ return new DebuggerBreakpointAnnotation(type, line, b);
+ }
+
@Override
public String getAnnotationType () {
return type;
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ThreadsCollector.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ThreadsCollector.java
index 4689901..d39efa8 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ThreadsCollector.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ThreadsCollector.java
@@ -68,7 +68,7 @@ public final class ThreadsCollector {
}
}
- CPPThread get(String id) {
+ public CPPThread get(String id) {
synchronized (threads) {
return threads.get(id);
}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ToolTipAnnotation.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ToolTipAnnotation.java
index 88f571c..9fadadb 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ToolTipAnnotation.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ToolTipAnnotation.java
@@ -37,6 +37,7 @@ import org.openide.util.RequestProcessor;
import org.netbeans.api.debugger.DebuggerManager;
import org.netbeans.spi.debugger.ui.EditorContextDispatcher;
+import org.netbeans.modules.nativeimage.spi.debug.filters.VariableDisplayer;
public class ToolTipAnnotation extends Annotation implements Runnable {
@@ -96,8 +97,11 @@ public class ToolTipAnnotation extends Annotation implements Runnable {
if (d == null || (frame = d.getCurrentFrame()) == null) {
return;
}
- frame.evaluateLazy(expression,
- variable -> {
+ frame.evaluateAsync(expression).thenAccept(variable -> {
+ VariableDisplayer displayer = currentEngine.lookupFirst(null, VariableDisplayer.class);
+ if (displayer != null) {
+ variable = displayer.displayed(variable)[0];
+ }
String value = variable.getValue();
if (!value.equals(expression)) {
String toolTipText;
@@ -109,9 +113,10 @@ public class ToolTipAnnotation extends Annotation implements Runnable {
}
firePropertyChange (PROP_SHORT_DESCRIPTION, null, toolTipText);
}
- }, exception -> {
+ }).exceptionally(exception -> {
String toolTipText = exception.getLocalizedMessage();
firePropertyChange (PROP_SHORT_DESCRIPTION, null, toolTipText);
+ return null;
});
}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/api/Debugger.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/api/Debugger.java
index f4f111f..03e5c62 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/api/Debugger.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/api/Debugger.java
@@ -21,8 +21,10 @@ package org.netbeans.modules.cpplite.debugger.api;
import java.io.File;
import java.io.IOException;
import java.util.List;
+import org.netbeans.api.debugger.DebuggerEngine;
import org.netbeans.modules.cpplite.debugger.CPPLiteDebugger;
import org.netbeans.modules.cpplite.debugger.CPPLiteDebuggerConfig;
+import org.openide.util.Pair;
/**
*
@@ -36,6 +38,8 @@ public class Debugger {
}
public static Process startInDebugger(List<String> command, File directory) throws IOException {
- return CPPLiteDebugger.startDebugging(new CPPLiteDebuggerConfig(command, directory)).second();
+ Pair<DebuggerEngine, Process> engineProcess = CPPLiteDebugger.startDebugging(new CPPLiteDebuggerConfig(command, directory, "gdb"));
+ engineProcess.first().lookupFirst(null, CPPLiteDebugger.class).execRun();
+ return engineProcess.second();
}
}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointAnnotationProvider.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointAnnotationProvider.java
index aac9137..b55783f 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointAnnotationProvider.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointAnnotationProvider.java
@@ -104,7 +104,7 @@ public class BreakpointAnnotationProvider extends DebuggerManagerAdapter impleme
for (Breakpoint breakpoint : DebuggerManager.getDebuggerManager().getBreakpoints()) {
if (breakpoint instanceof CPPLiteBreakpoint) {
CPPLiteBreakpoint b = (CPPLiteBreakpoint) breakpoint;
- if (isAt(b, fo)) {
+ if (!b.isHidden() && isAt(b, fo)) {
if (!breakpointToAnnotations.containsKey(b)) {
b.addPropertyChangeListener(this);
}
@@ -118,13 +118,13 @@ public class BreakpointAnnotationProvider extends DebuggerManagerAdapter impleme
}
private static boolean isAt(CPPLiteBreakpoint b, FileObject fo) {
- FileObject bfo = (FileObject) b.getLine().getLookup().lookup(FileObject.class);
+ FileObject bfo = b.getFileObject();
return fo.equals(bfo);
}
@Override
public void breakpointAdded(Breakpoint breakpoint) {
- if (breakpoint instanceof CPPLiteBreakpoint) {
+ if (breakpoint instanceof CPPLiteBreakpoint && !((CPPLiteBreakpoint) breakpoint).isHidden()) {
postAnnotationRefresh((CPPLiteBreakpoint) breakpoint, false, true);
breakpoint.addPropertyChangeListener (this);
}
@@ -132,7 +132,7 @@ public class BreakpointAnnotationProvider extends DebuggerManagerAdapter impleme
@Override
public void breakpointRemoved(Breakpoint breakpoint) {
- if (breakpoint instanceof CPPLiteBreakpoint) {
+ if (breakpoint instanceof CPPLiteBreakpoint && !((CPPLiteBreakpoint) breakpoint).isHidden()) {
breakpoint.removePropertyChangeListener (this);
postAnnotationRefresh((CPPLiteBreakpoint) breakpoint, true, false);
}
@@ -231,7 +231,10 @@ public class BreakpointAnnotationProvider extends DebuggerManagerAdapter impleme
String condition = getCondition(b);
boolean isConditional = condition.trim().length() > 0 || b.getHitCountFilteringStyle() != null;
String annotationType = getAnnotationType(b, isConditional, breakpointsActive);
- DebuggerBreakpointAnnotation annotation = new DebuggerBreakpointAnnotation (annotationType, b);
+ DebuggerBreakpointAnnotation annotation = DebuggerBreakpointAnnotation.create(annotationType, b);
+ if (annotation == null) {
+ return ;
+ }
Set<Annotation> bpAnnotations = breakpointToAnnotations.get(b);
if (bpAnnotations == null) {
Set<Annotation> set = new WeakSet<>();
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointModel.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointModel.java
index 6939797..11d1757 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointModel.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointModel.java
@@ -19,6 +19,7 @@
package org.netbeans.modules.cpplite.debugger.breakpoints;
+import java.io.File;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -65,9 +66,15 @@ public class BreakpointModel implements NodeModel {
public String getDisplayName (Object node) throws UnknownTypeException {
if (node instanceof CPPLiteBreakpoint) {
CPPLiteBreakpoint breakpoint = (CPPLiteBreakpoint) node;
- FileObject fileObject = breakpoint.getLine().getLookup().lookup(FileObject.class);
- return fileObject.getNameExt () + ":" +
- (breakpoint.getLine ().getLineNumber () + 1);
+ String nameExt;
+ FileObject fileObject = breakpoint.getFileObject();
+ if (fileObject != null) {
+ nameExt = fileObject.getNameExt();
+ } else {
+ File file = new File(breakpoint.getFilePath());
+ nameExt = file.getName();
+ }
+ return nameExt + ":" + breakpoint.getLineNumber();
}
throw new UnknownTypeException (node);
}
@@ -114,7 +121,7 @@ public class BreakpointModel implements NodeModel {
throws UnknownTypeException {
if (node instanceof CPPLiteBreakpoint) {
CPPLiteBreakpoint breakpoint = (CPPLiteBreakpoint) node;
- return breakpoint.getLine ().getDisplayName ();
+ return breakpoint.getFilePath() + ":" + breakpoint.getLineNumber();
}
throw new UnknownTypeException (node);
}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointsReader.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointsReader.java
index e0d9020..ae26933 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointsReader.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/BreakpointsReader.java
@@ -21,42 +21,50 @@ package org.netbeans.modules.cpplite.debugger.breakpoints;
import java.net.MalformedURLException;
import java.net.URL;
+
import org.netbeans.api.debugger.Breakpoint;
import org.netbeans.api.debugger.Properties;
import org.netbeans.spi.debugger.DebuggerServiceRegistration;
-import org.openide.cookies.LineCookie;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.URLMapper;
-import org.openide.loaders.DataObject;
-import org.openide.loaders.DataObjectNotFoundException;
-import org.openide.text.Line;
-
-/**
- *
- * @author Jan Jancura
- */
@DebuggerServiceRegistration(types={Properties.Reader.class})
public class BreakpointsReader implements Properties.Reader {
-
-
+
@Override
public String [] getSupportedClassNames () {
return new String[] {
- CPPLiteBreakpoint.class.getName (),
+ CPPLiteBreakpoint.class.getName (),
};
}
-
+
@Override
public Object read (String typeID, Properties properties) {
if (!(typeID.equals (CPPLiteBreakpoint.class.getName ())))
return null;
-
- Line line = getLine (
- properties.getString ("url", null),
- properties.getInt ("lineNumber", 1));
- if (line == null) return null;
- CPPLiteBreakpoint b = new CPPLiteBreakpoint (line);
+
+ CPPLiteBreakpoint b;
+ int lineNumber = properties.getInt("lineNumber", 0) + 1;
+ String url = properties.getString ("url", null);
+ if (url != null) {
+ FileObject fo;
+ try {
+ fo = URLMapper.findFileObject(new URL(url));
+ } catch (MalformedURLException ex) {
+ fo = null;
+ }
+ if (fo == null) {
+ // The user file is gone
+ return null;
+ }
+ b = CPPLiteBreakpoint.create(fo, lineNumber);
+ } else {
+ String filePath = properties.getString ("filePath", null);
+ if (filePath == null) {
+ return null;
+ }
+ b = CPPLiteBreakpoint.create(filePath, lineNumber);
+ }
b.setGroupName(
properties.getString (Breakpoint.PROP_GROUP_NAME, "")
);
@@ -79,18 +87,21 @@ public class BreakpointsReader implements Properties.Reader {
b.disable ();
return b;
}
-
+
@Override
public void write (Object object, Properties properties) {
CPPLiteBreakpoint b = (CPPLiteBreakpoint) object;
- FileObject fo = (FileObject) b.getLine().getLookup().lookup(FileObject.class);
- properties.setString("url", fo.toURL().toString());
+ FileObject fo = b.getFileObject();
+ if (fo != null) {
+ properties.setString("url", fo.toURL().toString());
+ }
+ properties.setString("filePath", b.getFilePath());
properties.setInt (
- "lineNumber",
- b.getLine ().getLineNumber ()
+ "lineNumber",
+ b.getLineNumber() - 1
);
properties.setString (
- Breakpoint.PROP_GROUP_NAME,
+ Breakpoint.PROP_GROUP_NAME,
b.getGroupName ()
);
properties.setBoolean (Breakpoint.PROP_ENABLED, b.isEnabled ());
@@ -103,32 +114,4 @@ public class BreakpointsReader implements Properties.Reader {
}
properties.setString(CPPLiteBreakpoint.PROP_CONDITION, condition);
}
-
-
- private Line getLine (String url, int lineNumber) {
- FileObject file;
- try {
- file = URLMapper.findFileObject (new URL (url));
- } catch (MalformedURLException e) {
- return null;
- }
- if (file == null) return null;
- DataObject dataObject;
- try {
- dataObject = DataObject.find (file);
- } catch (DataObjectNotFoundException ex) {
- return null;
- }
- if (dataObject == null) return null;
- LineCookie lineCookie = dataObject.getLookup().lookup(LineCookie.class);
- if (lineCookie == null) return null;
- Line.Set ls = lineCookie.getLineSet ();
- if (ls == null) return null;
- try {
- return ls.getCurrent (lineNumber);
- } catch (IndexOutOfBoundsException e) {
- } catch (IllegalArgumentException e) {
- }
- return null;
- }
}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/CPPLiteBreakpoint.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/CPPLiteBreakpoint.java
index 6f063ce..f4e6eb0 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/CPPLiteBreakpoint.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/CPPLiteBreakpoint.java
@@ -19,12 +19,15 @@
package org.netbeans.modules.cpplite.debugger.breakpoints;
+import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.debugger.Breakpoint;
import org.netbeans.api.debugger.DebuggerEngine;
import org.netbeans.api.debugger.DebuggerManager;
@@ -33,7 +36,11 @@ import org.netbeans.api.debugger.DebuggerManagerListener;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.modules.cpplite.debugger.CPPLiteDebugger;
+import org.openide.cookies.LineCookie;
import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.DataObjectNotFoundException;
import org.openide.text.Line;
import org.openide.util.NbBundle;
import org.openide.util.WeakListeners;
@@ -47,28 +54,101 @@ import org.openide.util.WeakListeners;
public final class CPPLiteBreakpoint extends Breakpoint {
public static final String PROP_CONDITION = "condition"; // NOI18N
+ public static final String PROP_HIDDEN = "hidden"; // NOI18N
- private volatile boolean enabled = true;
- private final Map<CPPLiteDebugger, String> ids = new HashMap<>();
- private final Line line;
+ private final AtomicBoolean enabled = new AtomicBoolean(true);
+ private final AtomicBoolean hidden = new AtomicBoolean(false);
+ @NullAllowed
+ private final FileObject fileObject; // The user file that contains the breakpoint
+ private final String filePath; // Path of the file to which MI breakpoint is submitted
+ private final int lineNumber; // The breakpoint line number
private volatile String condition;
- public CPPLiteBreakpoint (Line line) {
- this.line = line;
+ private CPPLiteBreakpoint (FileObject fileObject, String filePath, int lineNumber) {
+ this.fileObject = fileObject;
+ this.filePath = filePath;
+ this.lineNumber = lineNumber;
+ }
+
+ public static CPPLiteBreakpoint create(Line line) {
+ int lineNumber = line.getLineNumber() + 1;
+ FileObject fileObject = line.getLookup().lookup(FileObject.class);
+ String filePath = FileUtil.toFile(fileObject).getAbsolutePath();
+ return new CPPLiteBreakpoint(fileObject, filePath, lineNumber);
}
- public Line getLine () {
- return line;
+ /**
+ * Create a new CPP lite breakpoint based on a user file.
+ * @param fileObject the file path of the breakpoint
+ * @param lineNumber 1-based line number
+ * @return a new breakpoint.
+ */
+ public static CPPLiteBreakpoint create(FileObject fileObject, int lineNumber) {
+ String filePath = FileUtil.toFile(fileObject).getAbsolutePath();
+ return new CPPLiteBreakpoint(fileObject, filePath, lineNumber);
}
/**
+ * Create a new CPP lite breakpoint, that is not associated with a user file.
+ * @param filePath the file path of the breakpoint in the debuggee
+ * @param lineNumber 1-based line number
+ * @return a new breakpoint.
+ */
+ public static CPPLiteBreakpoint create(String filePath, int lineNumber) {
+ return new CPPLiteBreakpoint(null, filePath, lineNumber);
+ }
+
+ /**
+ * Get the file path of the breakpoint in the debuggee.
+ */
+ public String getFilePath() {
+ return filePath;
+ }
+
+ /**
+ * 1-based line number.
+ */
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ @CheckForNull
+ public FileObject getFileObject() {
+ return fileObject;
+ }
+
+ @CheckForNull
+ public Line getLine() {
+ FileObject fo = fileObject;
+ if (fo == null) {
+ return null;
+ }
+ DataObject dataObject;
+ try {
+ dataObject = DataObject.find(fo);
+ } catch (DataObjectNotFoundException ex) {
+ return null;
+ }
+ LineCookie lineCookie = dataObject.getLookup().lookup(LineCookie.class);
+ if (lineCookie != null) {
+ Line.Set ls = lineCookie.getLineSet ();
+ if (ls != null) {
+ try {
+ return ls.getCurrent(lineNumber - 1);
+ } catch (IndexOutOfBoundsException | IllegalArgumentException e) {
+ }
+ }
+ }
+ return null;
+ }
+ /**
* Test whether the breakpoint is enabled.
*
* @return <code>true</code> if so
*/
@Override
public boolean isEnabled () {
- return enabled;
+ return enabled.get();
}
/**
@@ -76,9 +156,9 @@ public final class CPPLiteBreakpoint extends Breakpoint {
*/
@Override
public void disable () {
- if (!enabled) return;
- enabled = false;
- firePropertyChange (PROP_ENABLED, Boolean.TRUE, Boolean.FALSE);
+ if (enabled.compareAndSet(true, false)) {
+ firePropertyChange (PROP_ENABLED, Boolean.TRUE, Boolean.FALSE);
+ }
}
/**
@@ -86,9 +166,9 @@ public final class CPPLiteBreakpoint extends Breakpoint {
*/
@Override
public void enable () {
- if (enabled) return;
- enabled = true;
- firePropertyChange (PROP_ENABLED, Boolean.FALSE, Boolean.TRUE);
+ if (enabled.compareAndSet(false, true)) {
+ firePropertyChange (PROP_ENABLED, Boolean.FALSE, Boolean.TRUE);
+ }
}
/**
@@ -117,6 +197,27 @@ public final class CPPLiteBreakpoint extends Breakpoint {
setValidity(validity, reason);
}
+ /**
+ * Gets value of hidden property.
+ *
+ * @return value of hidden property
+ */
+ public boolean isHidden() {
+ return hidden.get();
+ }
+
+ /**
+ * Sets value of hidden property.
+ *
+ * @param h a new value of hidden property
+ */
+ public void setHidden(boolean h) {
+ boolean old = hidden.getAndSet(h);
+ if (old != h) {
+ firePropertyChange(PROP_HIDDEN, old, h);
+ }
+ }
+
@Override
public GroupProperties getGroupProperties() {
return new CPPGroupProperties();
@@ -137,7 +238,7 @@ public final class CPPLiteBreakpoint extends Breakpoint {
}
private FileObject getFile() {
- return line.getLookup().lookup(FileObject.class);
+ return FileUtil.toFileObject(new File(filePath));
}
@Override
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/CPPLiteBreakpointActionProvider.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/CPPLiteBreakpointActionProvider.java
index c166e25..2402fe0 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/CPPLiteBreakpointActionProvider.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/CPPLiteBreakpointActionProvider.java
@@ -69,23 +69,30 @@ public class CPPLiteBreakpointActionProvider extends ActionsProviderSupport
@Override
public void doAction (Object action) {
Line line = getCurrentLine ();
- if (line == null) return ;
- Breakpoint[] breakpoints = DebuggerManager.getDebuggerManager ().
- getBreakpoints ();
+ if (line == null) {
+ return ;
+ }
+ Breakpoint[] breakpoints = DebuggerManager.getDebuggerManager().getBreakpoints ();
+ FileObject fo = line.getLookup().lookup(FileObject.class);
+ if (fo == null) {
+ return ;
+ }
+ int lineNumber = line.getLineNumber() + 1;
int i, k = breakpoints.length;
- for (i = 0; i < k; i++)
- if ( breakpoints [i] instanceof CPPLiteBreakpoint &&
- ((CPPLiteBreakpoint) breakpoints [i]).getLine ().equals (line)
- ) {
- DebuggerManager.getDebuggerManager ().removeBreakpoint
- (breakpoints [i]);
- break;
+ for (i = 0; i < k; i++) {
+ if (breakpoints[i] instanceof CPPLiteBreakpoint) {
+ CPPLiteBreakpoint cppb = (CPPLiteBreakpoint) breakpoints[i];
+ if (fo.equals(cppb.getFileObject()) && cppb.getLineNumber() == lineNumber) {
+ DebuggerManager.getDebuggerManager().removeBreakpoint(cppb);
+ break;
+ }
}
- if (i == k)
+ }
+ if (i == k) {
DebuggerManager.getDebuggerManager ().addBreakpoint (
- new CPPLiteBreakpoint (line)
+ CPPLiteBreakpoint.create(line)
);
- //S ystem.out.println("toggle");
+ }
}
/**
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/PersistenceManager.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/PersistenceManager.java
index d467600..d77c8f2 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/PersistenceManager.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/breakpoints/PersistenceManager.java
@@ -136,12 +136,15 @@ public class PersistenceManager implements LazyDebuggerManagerListener {
private static Breakpoint[] getBreakpoints () {
Breakpoint[] bs = DebuggerManager.getDebuggerManager ().
getBreakpoints ();
- int i, k = bs.length;
List<Breakpoint> bb = new ArrayList<>();
- for (i = 0; i < k; i++)
- // Don't store hidden breakpoints
- if (bs[i] instanceof CPPLiteBreakpoint)
- bb.add (bs [i]);
+ for (Breakpoint b : bs) {
+ if (b instanceof CPPLiteBreakpoint) {
+ // Don't store hidden breakpoints
+ if (!((CPPLiteBreakpoint) b).isHidden()) {
+ bb.add(b);
+ }
+ }
+ }
bs = new Breakpoint [bb.size ()];
return (Breakpoint[]) bb.toArray (bs);
}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/debuggingview/DebuggingModel.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/debuggingview/DebuggingModel.java
index 1db0f44..c86d1d5 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/debuggingview/DebuggingModel.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/debuggingview/DebuggingModel.java
@@ -128,7 +128,7 @@ public class DebuggingModel extends CachedChildrenTreeModel implements ExtendedN
return ((CPPThread) node).getName();
} else if (node instanceof CPPFrame) {
CPPFrame frame = (CPPFrame) node;
- return frame.functionName + "; " + frame.shortFileName + ":" + frame.line;
+ return frame.getName();
}
throw new UnknownTypeException (node);
}
@@ -143,7 +143,7 @@ public class DebuggingModel extends CachedChildrenTreeModel implements ExtendedN
return details;
} else if (node instanceof CPPFrame) {
CPPFrame frame = (CPPFrame) node;
- return frame.functionName + "; " + frame.fullFileName + ":" + frame.line;
+ return frame.getDescription();
}
throw new UnknownTypeException (node);
}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/models/CallStackModel.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/models/CallStackModel.java
index 017bef6..30768d9 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/models/CallStackModel.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/models/CallStackModel.java
@@ -19,6 +19,8 @@
package org.netbeans.modules.cpplite.debugger.models;
+import java.net.MalformedURLException;
+import java.net.URI;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.Action;
@@ -39,6 +41,9 @@ import org.netbeans.spi.viewmodel.TreeModel;
import org.netbeans.spi.viewmodel.ModelListener;
import org.netbeans.spi.viewmodel.UnknownTypeException;
import org.netbeans.spi.debugger.ui.Constants;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.filesystems.URLMapper;
import org.openide.text.Line;
import org.openide.util.NbBundle;
@@ -190,7 +195,7 @@ public class CallStackModel implements TreeModel, NodeModel, NodeActionsProvider
public String getDisplayName (Object node) throws UnknownTypeException {
if (node instanceof CPPFrame) {
CPPFrame frame = (CPPFrame) node;
- return frame.functionName + "; " + frame.shortFileName + ":" + frame.line;
+ return frame.getName();
}
if (node == ROOT) {
return ROOT;
@@ -232,7 +237,7 @@ public class CallStackModel implements TreeModel, NodeModel, NodeActionsProvider
public String getShortDescription (Object node) throws UnknownTypeException {
if (node instanceof CPPFrame) {
CPPFrame frame = (CPPFrame) node;
- return frame.functionName + "; " + frame.fullFileName + ":" + frame.line;
+ return frame.getDescription();
}
throw new UnknownTypeException (node);
}
@@ -295,7 +300,23 @@ public class CallStackModel implements TreeModel, NodeModel, NodeActionsProvider
if (columnID == Constants.CALL_STACK_FRAME_LOCATION_COLUMN_ID) {
if (node instanceof CPPFrame) {
CPPFrame frame = (CPPFrame) node;
- return frame.fullFileName + ":" + frame.line;
+ URI sourceURI = frame.getSourceURI();
+ if (sourceURI == null) {
+ return "";
+ }
+ String sourceName;
+ try {
+ FileObject file = URLMapper.findFileObject(sourceURI.toURL());
+ sourceName = file.getPath();
+ } catch (MalformedURLException ex) {
+ sourceName = sourceURI.toString();
+ }
+ int line = frame.getLine();
+ if (line > 0) {
+ return sourceName + ':' + line;
+ } else {
+ return sourceName + ":?";
+ }
}
}
throw new UnknownTypeException (node);
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/models/VariablesModel.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/models/VariablesModel.java
index cc0666b..ed47d5a 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/models/VariablesModel.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/models/VariablesModel.java
@@ -27,7 +27,7 @@ import org.netbeans.modules.cpplite.debugger.CPPFrame;
import org.netbeans.modules.cpplite.debugger.CPPLiteDebugger;
import org.netbeans.modules.cpplite.debugger.CPPLiteDebugger.StateListener;
import org.netbeans.modules.cpplite.debugger.CPPThread;
-import org.netbeans.modules.cpplite.debugger.CPPVariable;
+import org.netbeans.modules.nativeimage.api.debug.NIVariable;
import org.netbeans.spi.debugger.ContextProvider;
import org.netbeans.spi.debugger.DebuggerServiceRegistration;
@@ -40,6 +40,7 @@ import org.netbeans.spi.viewmodel.UnknownTypeException;
import org.openide.util.NbBundle;
import org.openide.util.WeakListeners;
+import org.netbeans.modules.nativeimage.spi.debug.filters.VariableDisplayer;
/**
*
@@ -56,12 +57,14 @@ public class VariablesModel implements TreeModel, NodeModel, TableModel, StateLi
private final CPPLiteDebugger debugger;
private final List<ModelListener> listeners = new CopyOnWriteArrayList<>();
+ private final VariableDisplayer displayer;
private volatile CPPFrame currentFrame;
public VariablesModel (ContextProvider contextProvider) {
debugger = contextProvider.lookupFirst(null, CPPLiteDebugger.class);
debugger.addStateListener(WeakListeners.create(StateListener.class, this, debugger));
+ displayer = contextProvider.lookupFirst(null, VariableDisplayer.class);
currentFrame = debugger.getCurrentFrame();
}
@@ -96,24 +99,31 @@ public class VariablesModel implements TreeModel, NodeModel, TableModel, StateLi
*/
@Override
public Object[] getChildren (Object parent, int from, int to) throws UnknownTypeException {
- CPPVariable parentVar;
+ NIVariable parentVar;
if (parent == ROOT) {
parentVar = null;
- } else if (parent instanceof CPPVariable) {
- parentVar = (CPPVariable) parent;
+ } else if (parent instanceof NIVariable) {
+ parentVar = (NIVariable) parent;
} else {
throw new UnknownTypeException (parent);
}
CPPFrame frame = currentFrame;
if (frame != null) {
- Map<String, CPPVariable> variables = (parentVar == null) ? frame.getVariables() : parentVar.getChildrenVariables();
- Object[] array = variables.values().toArray();
- if (array.length == 1 && array[0] == null) {
- // Some error / message
- return new Object[]{variables.keySet().iterator().next()};
+ NIVariable[] array;
+ if (parentVar == null) {
+ Map<String, NIVariable> variables = frame.getVariables();
+ array = variables.values().toArray(new NIVariable[0]);
+ if (array.length == 1 && array[0] == null) {
+ // Some error / message
+ return new Object[]{variables.keySet().iterator().next()};
+ }
} else {
- return array;
+ array = parentVar.getChildren(from, to);
}
+ if (displayer != null) {
+ array = displayer.displayed(array);
+ }
+ return array;
} else {
return NO_VARS;
}
@@ -134,8 +144,8 @@ public class VariablesModel implements TreeModel, NodeModel, TableModel, StateLi
if (node instanceof String) {
return true;
}
- if (node instanceof CPPVariable) {
- return ((CPPVariable) node).getNumChildren() == 0;
+ if (node instanceof NIVariable) {
+ return ((NIVariable) node).getNumChildren() == 0;
}
throw new UnknownTypeException (node);
}
@@ -158,8 +168,8 @@ public class VariablesModel implements TreeModel, NodeModel, TableModel, StateLi
public int getChildrenCount (Object node) throws UnknownTypeException {
if (node == ROOT) {
return Integer.MAX_VALUE;
- } else if (node instanceof CPPVariable) {
- return ((CPPVariable) node).getNumChildren();
+ } else if (node instanceof NIVariable) {
+ return ((NIVariable) node).getNumChildren();
}
throw new UnknownTypeException (node);
}
@@ -201,8 +211,8 @@ public class VariablesModel implements TreeModel, NodeModel, TableModel, StateLi
if (node instanceof String) {
return (String) node;
}
- if (node instanceof CPPVariable) {
- return ((CPPVariable) node).getName();
+ if (node instanceof NIVariable) {
+ return ((NIVariable) node).getName();
}
throw new UnknownTypeException (node);
}
@@ -218,7 +228,7 @@ public class VariablesModel implements TreeModel, NodeModel, TableModel, StateLi
*/
@Override
public String getIconBase (Object node) throws UnknownTypeException {
- if (node instanceof CPPVariable) {
+ if (node instanceof NIVariable) {
return LOCAL;
}
if (node instanceof String) {
@@ -265,13 +275,13 @@ public class VariablesModel implements TreeModel, NodeModel, TableModel, StateLi
@Override
public Object getValueAt (Object node, String columnID) throws UnknownTypeException {
if (columnID.equals ("LocalsValue")) {
- if (node instanceof CPPVariable) {
- return ((CPPVariable) node).getValue();
+ if (node instanceof NIVariable) {
+ return ((NIVariable) node).getValue();
}
}
if (columnID.equals ("LocalsType")) {
- if (node instanceof CPPVariable) {
- return ((CPPVariable) node).getType();
+ if (node instanceof NIVariable) {
+ return ((NIVariable) node).getType();
}
}
if (node instanceof String) {
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/models/WatchesModel.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/models/WatchesModel.java
index abf9740..56707c4 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/models/WatchesModel.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/models/WatchesModel.java
@@ -32,8 +32,8 @@ import org.netbeans.modules.cpplite.debugger.CPPFrame;
import org.netbeans.modules.cpplite.debugger.CPPLiteDebugger;
import org.netbeans.modules.cpplite.debugger.CPPLiteDebugger.StateListener;
import org.netbeans.modules.cpplite.debugger.CPPThread;
-import org.netbeans.modules.cpplite.debugger.CPPVariable;
-import org.netbeans.modules.cpplite.debugger.EvaluateException;
+import org.netbeans.modules.nativeimage.api.debug.EvaluateException;
+import org.netbeans.modules.nativeimage.api.debug.NIVariable;
import org.netbeans.spi.debugger.ContextProvider;
import org.netbeans.spi.debugger.DebuggerServiceRegistration;
import org.netbeans.spi.viewmodel.ModelEvent;
@@ -99,7 +99,7 @@ public class WatchesModel implements TreeModelFilter, NodeModelFilter, TableMode
if (ew != null) {
switch (ew.getStatus()) {
case READY:
- CPPVariable result = ew.getResult();
+ NIVariable result = ew.getResult();
return result.getNumChildren();
}
}
@@ -115,7 +115,7 @@ public class WatchesModel implements TreeModelFilter, NodeModelFilter, TableMode
if (ew != null) {
switch (ew.getStatus()) {
case READY:
- CPPVariable result = ew.getResult();
+ NIVariable result = ew.getResult();
return result.getNumChildren() == 0;
}
}
@@ -171,7 +171,7 @@ public class WatchesModel implements TreeModelFilter, NodeModelFilter, TableMode
ew.startEvaluate();
switch (ew.getStatus()) {
case READY:
- CPPVariable result = ew.getResult();
+ NIVariable result = ew.getResult();
return ew.getExpression() + " = " + result.getValue();
case FAILED:
EvaluateException exc = ew.getException();
@@ -212,7 +212,7 @@ public class WatchesModel implements TreeModelFilter, NodeModelFilter, TableMode
ew.startEvaluate();
switch (ew.getStatus()) {
case READY:
- CPPVariable result = ew.getResult();
+ NIVariable result = ew.getResult();
if (showValue) {
return result.getValue();
} else {
@@ -342,7 +342,7 @@ public class WatchesModel implements TreeModelFilter, NodeModelFilter, TableMode
private final Watch watch;
private volatile AtomicReference<EvalStatus> status = new AtomicReference<>(EvalStatus.NEW);
private volatile String expression;
- private volatile CPPVariable result;
+ private volatile NIVariable result;
private volatile EvaluateException exception;
private EvalWatch(Watch watch) {
@@ -364,16 +364,17 @@ public class WatchesModel implements TreeModelFilter, NodeModelFilter, TableMode
exception = null;
String expression = watch.getExpression();
this.expression = expression;
- frame.evaluateLazy(expression,
- (CPPVariable variable) -> {
+ frame.evaluateAsync(expression).thenAccept(
+ (NIVariable variable) -> {
result = variable;
status.set(EvalStatus.READY);
fireChanged(watch);
- },
- (EvaluateException exc) -> {
- exception = exc;
+ }).exceptionally(
+ exc -> {
+ exception = (EvaluateException) exc;
status.set(EvalStatus.FAILED);
fireChanged(watch);
+ return null;
});
}
}
@@ -382,7 +383,7 @@ public class WatchesModel implements TreeModelFilter, NodeModelFilter, TableMode
return expression;
}
- CPPVariable getResult() {
+ NIVariable getResult() {
return result;
}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ni/NIBreakpoints.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ni/NIBreakpoints.java
new file mode 100644
index 0000000..754ccc6
--- /dev/null
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ni/NIBreakpoints.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cpplite.debugger.ni;
+
+import java.util.ArrayList;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.netbeans.api.debugger.Breakpoint;
+import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.modules.cpplite.debugger.breakpoints.CPPLiteBreakpoint;
+import org.netbeans.modules.nativeimage.api.debug.NILineBreakpointDescriptor;
+
+/**
+ *
+ * @author martin
+ */
+final class NIBreakpoints {
+
+ private final Map<Object, CPPLiteBreakpoint> ni2C = new IdentityHashMap<>();
+
+ Breakpoint addLineBreakpoint(Object key, NILineBreakpointDescriptor bd) {
+ CPPLiteBreakpoint breakpoint;
+ boolean isNew;
+ synchronized (ni2C) {
+ breakpoint = ni2C.get(key);
+ isNew = breakpoint == null;
+ if (isNew) {
+ breakpoint = CPPLiteBreakpoint.create(bd.getFilePath(), bd.getLine());
+ ni2C.put(key, breakpoint);
+ }
+ }
+ // TODO Update fileUrl and line number
+ if (bd.isEnabled()) {
+ breakpoint.enable();
+ } else {
+ breakpoint.disable();
+ }
+ breakpoint.setCondition(bd.getCondition());
+ breakpoint.setHidden(bd.isHidden());
+ if (isNew) {
+ DebuggerManager.getDebuggerManager().addBreakpoint(breakpoint);
+ }
+ return breakpoint;
+ }
+
+ void removeBreakpoint(Object key) {
+ CPPLiteBreakpoint breakpoint;
+ synchronized (ni2C) {
+ breakpoint = ni2C.remove(key);
+ }
+ if (breakpoint != null) {
+ DebuggerManager.getDebuggerManager().removeBreakpoint(breakpoint);
+ }
+ }
+
+ void dispose() {
+ List<CPPLiteBreakpoint> cbs;
+ synchronized (ni2C) {
+ cbs = new ArrayList<>(ni2C.size());
+ cbs.addAll(ni2C.values());
+ ni2C.clear();
+ }
+ for (CPPLiteBreakpoint cb : cbs) {
+ DebuggerManager.getDebuggerManager().removeBreakpoint(cb);
+ }
+ }
+}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ni/NIDebuggerProviderImpl.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ni/NIDebuggerProviderImpl.java
new file mode 100644
index 0000000..f051d93
--- /dev/null
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ni/NIDebuggerProviderImpl.java
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.cpplite.debugger.ni;
+
+import java.io.File;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+
+import org.netbeans.api.debugger.Breakpoint;
+import org.netbeans.api.debugger.DebuggerEngine;
+import org.netbeans.api.extexecution.ExecutionDescriptor;
+import org.netbeans.api.extexecution.ExecutionService;
+import org.netbeans.modules.cpplite.debugger.CPPFrame;
+import org.netbeans.modules.cpplite.debugger.CPPLiteDebugger;
+import org.netbeans.modules.cpplite.debugger.CPPLiteDebuggerConfig;
+import org.netbeans.modules.cpplite.debugger.CPPThread;
+import org.netbeans.modules.nativeimage.api.debug.EvaluateException;
+import org.netbeans.modules.nativeimage.api.debug.NIFrame;
+import org.netbeans.modules.nativeimage.api.debug.NILineBreakpointDescriptor;
+import org.netbeans.modules.nativeimage.api.debug.NIVariable;
+import org.netbeans.modules.nativeimage.spi.debug.NIDebuggerProvider;
+import org.netbeans.modules.nativeimage.spi.debug.filters.FrameDisplayer;
+
+import org.openide.LifecycleManager;
+import org.openide.util.Pair;
+import org.openide.util.RequestProcessor;
+import org.netbeans.modules.nativeimage.spi.debug.filters.VariableDisplayer;
+
+/**
+ *
+ * @author martin
+ */
+public class NIDebuggerProviderImpl implements NIDebuggerProvider {
+
+ private final NIBreakpoints breakpointsHandler = new NIBreakpoints();
+ private volatile CPPLiteDebugger debugger;
+ private volatile FrameDisplayer frameDisplayer;
+ private volatile VariableDisplayer variablesDisplayer;
+ private final RequestProcessor varDisplayerRP = new RequestProcessor(NIDebuggerProvider.class);
+
+ public NIDebuggerProviderImpl() {
+ }
+
+ @Override
+ public Breakpoint addLineBreakpoint(Object id, NILineBreakpointDescriptor breakpointDescriptor) {
+ return breakpointsHandler.addLineBreakpoint(id, breakpointDescriptor);
+ }
+
+ @Override
+ public void removeBreakpoint(Object id) {
+ breakpointsHandler.removeBreakpoint(id);
+ }
+
+ @Override
+ public void setFrameDisplayer(FrameDisplayer frameDisplayer) {
+ this.frameDisplayer = frameDisplayer;
+ }
+
+ @Override
+ public void setVariablesDisplayer(VariableDisplayer variablesDisplayer) {
+ this.variablesDisplayer = variablesDisplayer;
+ }
+
+ @Override
+ public CompletableFuture<Void> start(List<String> command, File workingDirectory, String miDebugger, String displayName, ExecutionDescriptor executionDescriptor, Consumer<DebuggerEngine> startedEngine) {
+ if (debugger != null) {
+ throw new IllegalStateException("Debugger has started already.");
+ }
+ if (executionDescriptor == null) {
+ executionDescriptor = new ExecutionDescriptor()
+ .showProgress(true)
+ .showSuspended(true)
+ .frontWindowOnError(true)
+ .controllable(true);
+ }
+ CompletableFuture<Void> completed = new CompletableFuture<>();
+ ExecutionService.newService(() -> {
+ LifecycleManager.getDefault().saveAll();
+ Pair<DebuggerEngine, Process> engineProcess = CPPLiteDebugger.startDebugging(
+ new CPPLiteDebuggerConfig(command, workingDirectory, miDebugger),
+ frameDisplayer,
+ variablesDisplayer);
+ DebuggerEngine engine = engineProcess.first();
+ CPPLiteDebugger debugger = engine.lookupFirst(null, CPPLiteDebugger.class);
+ this.debugger = debugger;
+ if (startedEngine != null) {
+ startedEngine.accept(engine);
+ }
+ debugger.addStateListener(new CPPLiteDebugger.StateListener() {
+ @Override
+ public void currentThread(CPPThread thread) {}
+
+ @Override
+ public void currentFrame(CPPFrame frame) {}
+
+ @Override
+ public void suspended(boolean suspended) {}
+
+ @Override
+ public void finished() {
+ breakpointsHandler.dispose();
+ completed.complete(null);
+ }
+ });
+ debugger.execRun();
+ return engineProcess.second();
+ }, executionDescriptor, displayName).run();
+ return completed;
+ }
+
+ @Override
+ public CompletableFuture<NIVariable> evaluateAsync(String expression, String resultName, NIFrame frame) {
+ CompletableFuture<NIVariable> result = new CompletableFuture<>();
+ CPPFrame cframe;
+ if (frame != null) {
+ CPPThread thread = debugger.getThreads().get(frame.getThreadId());
+ if (thread == null) {
+ result.completeExceptionally(new EvaluateException("No thread " + frame.getThreadId()));
+ return result;
+ }
+ try {
+ cframe = (CPPFrame) thread.getFrames().get(frame.getLevel());
+ } catch (IndexOutOfBoundsException ioobex) {
+ result.completeExceptionally(new EvaluateException(ioobex.getLocalizedMessage()));
+ return result;
+ }
+ } else {
+ cframe = debugger.getCurrentFrame();
+ }
+ cframe.evaluateAsync(expression, resultName).thenAccept(
+ rawResult -> {
+ // We must not run the VariableDisplayer synchronously with the MI command thread
+ varDisplayerRP.post(() -> {
+ NIVariable[] variables = variablesDisplayer.displayed(rawResult);
+ NIVariable variable = (variables.length > 0) ? variables[0] : rawResult;
+ result.complete(variable);
+ });
+ }).exceptionally(
+ exception -> {
+ result.completeExceptionally(exception);
+ return null;
+ });
+ return result;
+ }
+
+ @Override
+ public String readMemory(String address, long offset, int length) {
+ return debugger.readMemory(address, offset, length);
+ }
+
+ @Override
+ public String getVersion() {
+ return debugger.getVersion();
+ }
+}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ni/NIDebuggerServiceProviderImpl.java
similarity index 61%
copy from cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java
copy to cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ni/NIDebuggerServiceProviderImpl.java
index 0fc9c76..7a8be49 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ni/NIDebuggerServiceProviderImpl.java
@@ -16,17 +16,22 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.netbeans.modules.cpplite.debugger;
+package org.netbeans.modules.cpplite.debugger.ni;
-public final class EvaluateException extends Exception {
+import org.netbeans.modules.nativeimage.spi.debug.NIDebuggerProvider;
+import org.netbeans.modules.nativeimage.spi.debug.NIDebuggerServiceProvider;
+import org.openide.util.lookup.ServiceProvider;
- /**
- * Constructs an instance of <code>EvaluateException</code> with the
- * specified detail message.
- *
- * @param msg the detail message.
- */
- EvaluateException(String msg) {
- super(msg);
+/**
+ *
+ * @author martin
+ */
+@ServiceProvider(service = NIDebuggerServiceProvider.class)
+public class NIDebuggerServiceProviderImpl implements NIDebuggerServiceProvider {
+
+ @Override
+ public NIDebuggerProvider create() {
+ return new NIDebuggerProviderImpl();
}
+
}
diff --git a/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/AbstractDebugTest.java b/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/AbstractDebugTest.java
index 2d9d4bd..eb1e626 100644
--- a/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/AbstractDebugTest.java
+++ b/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/AbstractDebugTest.java
@@ -51,7 +51,7 @@ public abstract class AbstractDebugTest extends NbTestCase {
}
protected final void startDebugging(String name, File wd) throws IOException {
- engine = CPPLiteDebugger.startDebugging(new CPPLiteDebuggerConfig(Arrays.asList(new File(wd, name).getAbsolutePath()), wd)).first();
+ engine = CPPLiteDebugger.startDebugging(new CPPLiteDebuggerConfig(Arrays.asList(new File(wd, name).getAbsolutePath()), wd, "gdb")).first();
debugger = engine.lookupFirst(null, CPPLiteDebugger.class);
debugger.addStateListener(new CPPLiteDebugger.StateListener() {
@Override
@@ -80,6 +80,7 @@ public abstract class AbstractDebugTest extends NbTestCase {
public void currentFrame(CPPFrame frame) {
}
});
+ debugger.execRun();
}
protected final void waitSuspended(int count) throws InterruptedException {
diff --git a/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/BreakpointsTest.java b/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/BreakpointsTest.java
index f80bee8..d22f578 100644
--- a/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/BreakpointsTest.java
+++ b/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/BreakpointsTest.java
@@ -76,8 +76,8 @@ public class BreakpointsTest extends AbstractDebugTest {
compileC("breakpoints", wd);
LineCookie lc = DataObject.find(source).getLookup().lookup(LineCookie.class);
assertNotNull(lc);
- CPPLiteBreakpoint bp8 = new CPPLiteBreakpoint(lc.getLineSet().getCurrent(7));
- CPPLiteBreakpoint bp9 = new CPPLiteBreakpoint(lc.getLineSet().getCurrent(8));
+ CPPLiteBreakpoint bp8 = CPPLiteBreakpoint.create(lc.getLineSet().getCurrent(7));
+ CPPLiteBreakpoint bp9 = CPPLiteBreakpoint.create(lc.getLineSet().getCurrent(8));
bp9.disable();
DebuggerManager.getDebuggerManager().addBreakpoint(bp8);
DebuggerManager.getDebuggerManager().addBreakpoint(bp9);
@@ -98,7 +98,7 @@ public class BreakpointsTest extends AbstractDebugTest {
waitSuspended(3);
assertStoppedAt(source.toURI(), 9);
- CPPLiteBreakpoint bp10 = new CPPLiteBreakpoint(lc.getLineSet().getCurrent(9));
+ CPPLiteBreakpoint bp10 = CPPLiteBreakpoint.create(lc.getLineSet().getCurrent(9));
DebuggerManager.getDebuggerManager().addBreakpoint(bp10);
engine.getActionsManager().doAction(ActionsManager.ACTION_CONTINUE);
@@ -116,7 +116,7 @@ public class BreakpointsTest extends AbstractDebugTest {
bp10.disable();
- bp8 = new CPPLiteBreakpoint(lc.getLineSet().getCurrent(7));
+ bp8 = CPPLiteBreakpoint.create(lc.getLineSet().getCurrent(7));
DebuggerManager.getDebuggerManager().addBreakpoint(bp8);
engine.getActionsManager().doAction(ActionsManager.ACTION_CONTINUE);
diff --git a/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/StepTest.java b/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/StepTest.java
index a2042dd..307af7a 100644
--- a/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/StepTest.java
+++ b/cpplite/cpplite.debugger/test/unit/src/org/netbeans/modules/cpplite/debugger/StepTest.java
@@ -72,7 +72,7 @@ public class StepTest extends AbstractDebugTest {
compileCPP("main", wd);
LineCookie lc = DataObject.find(source).getLookup().lookup(LineCookie.class);
assertNotNull(lc);
- DebuggerManager.getDebuggerManager().addBreakpoint(new CPPLiteBreakpoint(lc.getLineSet().getCurrent(4)));
+ DebuggerManager.getDebuggerManager().addBreakpoint(CPPLiteBreakpoint.create(lc.getLineSet().getCurrent(4)));
startDebugging("main", wd);
waitSuspended(1);
diff --git a/cpplite/cpplite.project/src/org/netbeans/modules/cpplite/project/ActionProviderImpl.java b/cpplite/cpplite.project/src/org/netbeans/modules/cpplite/project/ActionProviderImpl.java
index cdcc5dc..428f4a8 100644
--- a/cpplite/cpplite.project/src/org/netbeans/modules/cpplite/project/ActionProviderImpl.java
+++ b/cpplite/cpplite.project/src/org/netbeans/modules/cpplite/project/ActionProviderImpl.java
@@ -90,7 +90,7 @@ public class ActionProviderImpl implements ActionProvider {
}, executionDescriptor, ProjectUtils.getInformation(prj).getDisplayName() + " - " + command).run();
}
- private String quote(String s) {
+ private static String quote(String s) {
return s.replace("_", "_u_").replace(" ", "_s_");
}
diff --git a/ide/ide.kit/nbproject/project.xml b/ide/ide.kit/nbproject/project.xml
index cdd6261..3b19e47 100644
--- a/ide/ide.kit/nbproject/project.xml
+++ b/ide/ide.kit/nbproject/project.xml
@@ -195,6 +195,13 @@
</run-dependency>
</dependency>
<dependency>
+ <code-name-base>org.netbeans.modules.nativeimage.api</code-name-base>
+ <run-dependency>
+ <release-version>0</release-version>
+ <specification-version>0.1</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
<code-name-base>org.netbeans.modules.options.editor</code-name-base>
<run-dependency>
<release-version>1</release-version>
diff --git a/ide/nativeimage.api/build.xml b/ide/nativeimage.api/build.xml
new file mode 100644
index 0000000..13ce273
--- /dev/null
+++ b/ide/nativeimage.api/build.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<!-- You may freely edit this file. See harness/README in the NetBeans platform -->
+<!-- for some information on what you could do (e.g. targets to override). -->
+<!-- If you delete this file and reopen the project it will be recreated. -->
+<project name="ide/nativeimage.api" default="build" basedir=".">
+ <description>Builds, tests, and runs the project org.netbeans.modules.nativeimage.api.</description>
+ <import file="../../nbbuild/templates/projectized.xml"/>
+</project>
diff --git a/ide/nativeimage.api/manifest.mf b/ide/nativeimage.api/manifest.mf
new file mode 100644
index 0000000..fdfa01c
--- /dev/null
+++ b/ide/nativeimage.api/manifest.mf
@@ -0,0 +1,6 @@
+Manifest-Version: 1.0
+AutoUpdate-Show-In-Client: false
+OpenIDE-Module: org.netbeans.modules.nativeimage.api/0
+OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/nativeimage/api/Bundle.properties
+OpenIDE-Module-Specification-Version: 0.1
+
diff --git a/ide/nativeimage.api/nbproject/project.properties b/ide/nativeimage.api/nbproject/project.properties
new file mode 100644
index 0000000..5137752
--- /dev/null
+++ b/ide/nativeimage.api/nbproject/project.properties
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+javac.source=1.8
+javac.compilerargs=-Xlint -Xlint:-serial
diff --git a/cpplite/cpplite.debugger/nbproject/project.xml b/ide/nativeimage.api/nbproject/project.xml
similarity index 55%
copy from cpplite/cpplite.debugger/nbproject/project.xml
copy to ide/nativeimage.api/nbproject/project.xml
index d360c06..f9f0149 100644
--- a/cpplite/cpplite.debugger/nbproject/project.xml
+++ b/ide/nativeimage.api/nbproject/project.xml
@@ -23,7 +23,7 @@
<type>org.netbeans.modules.apisupport.project</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
- <code-name-base>org.netbeans.modules.cpplite.debugger</code-name-base>
+ <code-name-base>org.netbeans.modules.nativeimage.api</code-name-base>
<module-dependencies>
<dependency>
<code-name-base>org.netbeans.api.annotations.common</code-name-base>
@@ -40,15 +40,16 @@
<compile-dependency/>
<run-dependency>
<release-version>1</release-version>
- <specification-version>1.63</specification-version>
+ <specification-version>1.67</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.netbeans.modules.dlight.nativeexecution</code-name-base>
+ <code-name-base>org.netbeans.modules.extexecution</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>1.48</specification-version>
+ <release-version>2</release-version>
+ <specification-version>1.59</specification-version>
</run-dependency>
</dependency>
<dependency>
@@ -61,32 +62,6 @@
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.netbeans.spi.debugger.ui</code-name-base>
- <build-prerequisite/>
- <compile-dependency/>
- <run-dependency>
- <release-version>1</release-version>
- <specification-version>2.62</specification-version>
- </run-dependency>
- </dependency>
- <dependency>
- <code-name-base>org.netbeans.spi.viewmodel</code-name-base>
- <build-prerequisite/>
- <compile-dependency/>
- <run-dependency>
- <release-version>2</release-version>
- <specification-version>1.59</specification-version>
- </run-dependency>
- </dependency>
- <dependency>
- <code-name-base>org.openide.awt</code-name-base>
- <build-prerequisite/>
- <compile-dependency/>
- <run-dependency>
- <specification-version>7.76</specification-version>
- </run-dependency>
- </dependency>
- <dependency>
<code-name-base>org.openide.filesystems</code-name-base>
<build-prerequisite/>
<compile-dependency/>
@@ -95,43 +70,11 @@
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.loaders</code-name-base>
- <build-prerequisite/>
- <compile-dependency/>
- <run-dependency>
- <specification-version>7.76</specification-version>
- </run-dependency>
- </dependency>
- <dependency>
- <code-name-base>org.openide.modules</code-name-base>
- <build-prerequisite/>
- <compile-dependency/>
- <run-dependency>
- <specification-version>7.56</specification-version>
- </run-dependency>
- </dependency>
- <dependency>
- <code-name-base>org.openide.nodes</code-name-base>
- <build-prerequisite/>
- <compile-dependency/>
- <run-dependency>
- <specification-version>7.53</specification-version>
- </run-dependency>
- </dependency>
- <dependency>
- <code-name-base>org.openide.text</code-name-base>
- <build-prerequisite/>
- <compile-dependency/>
- <run-dependency>
- <specification-version>6.75</specification-version>
- </run-dependency>
- </dependency>
- <dependency>
<code-name-base>org.openide.util</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>9.15</specification-version>
+ <specification-version>9.19</specification-version>
</run-dependency>
</dependency>
<dependency>
@@ -142,22 +85,6 @@
<specification-version>8.41</specification-version>
</run-dependency>
</dependency>
- <dependency>
- <code-name-base>org.openide.util.ui</code-name-base>
- <build-prerequisite/>
- <compile-dependency/>
- <run-dependency>
- <specification-version>9.16</specification-version>
- </run-dependency>
- </dependency>
- <dependency>
- <code-name-base>org.openide.windows</code-name-base>
- <build-prerequisite/>
- <compile-dependency/>
- <run-dependency>
- <specification-version>6.85</specification-version>
- </run-dependency>
- </dependency>
</module-dependencies>
<test-dependencies>
<test-type>
@@ -186,13 +113,16 @@
</test-type>
</test-dependencies>
<friend-packages>
- <friend>org.netbeans.modules.cpplite.project</friend>
- <package>org.netbeans.modules.cpplite.debugger.api</package>
+ <friend>org.netbeans.modules.cpplite.debugger</friend>
+ <friend>org.netbeans.modules.gradle.java</friend>
+ <friend>org.netbeans.modules.java.lsp.server</friend>
+ <friend>org.netbeans.modules.java.nativeimage.debugger</friend>
+ <package>org.netbeans.modules.nativeimage.api</package>
+ <package>org.netbeans.modules.nativeimage.api.debug</package>
+ <package>org.netbeans.modules.nativeimage.spi</package>
+ <package>org.netbeans.modules.nativeimage.spi.debug</package>
+ <package>org.netbeans.modules.nativeimage.spi.debug.filters</package>
</friend-packages>
- <class-path-extension>
- <runtime-relative-path>ext/cpplite-mi-f8f8250283be.jar</runtime-relative-path>
- <binary-origin>external/cpplite-mi-f8f8250283be.jar</binary-origin>
- </class-path-extension>
</data>
</configuration>
</project>
diff --git a/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/Bundle.properties b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/Bundle.properties
new file mode 100644
index 0000000..139a1c1
--- /dev/null
+++ b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/Bundle.properties
@@ -0,0 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# manifest's description entries
+OpenIDE-Module-Display-Category=Base IDE
+OpenIDE-Module-Name=Native Image API
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/EvaluateException.java
similarity index 66%
copy from cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java
copy to ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/EvaluateException.java
index 0fc9c76..1d542bb 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java
+++ b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/EvaluateException.java
@@ -16,17 +16,35 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.netbeans.modules.cpplite.debugger;
+package org.netbeans.modules.nativeimage.api.debug;
-public final class EvaluateException extends Exception {
+/**
+ * Thrown when evaluation in the native debugger fails.
+ *
+ * @since 1.0
+ */
+public class EvaluateException extends Exception {
/**
* Constructs an instance of <code>EvaluateException</code> with the
* specified detail message.
*
* @param msg the detail message.
+ * @since 1.0
*/
- EvaluateException(String msg) {
+ public EvaluateException(String msg) {
super(msg);
}
+
+ /**
+ * Constructs an instance of <code>EvaluateException</code> from an
+ * existing exception.
+ *
+ * @param t exception.
+ * @since 1.0
+ */
+ public EvaluateException(Throwable t) {
+ super(t.getLocalizedMessage(), t);
+
+ }
}
diff --git a/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/NIDebugger.java b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/NIDebugger.java
new file mode 100644
index 0000000..f980655
--- /dev/null
+++ b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/NIDebugger.java
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.nativeimage.api.debug;
+
+import java.io.File;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.function.Consumer;
+
+import org.netbeans.api.debugger.Breakpoint;
+import org.netbeans.api.debugger.DebuggerEngine;
+import org.netbeans.api.extexecution.ExecutionDescriptor;
+import org.netbeans.modules.nativeimage.spi.debug.NIDebuggerProvider;
+import org.netbeans.modules.nativeimage.spi.debug.NIDebuggerServiceProvider;
+import org.netbeans.modules.nativeimage.spi.debug.filters.FrameDisplayer;
+import org.openide.util.Lookup;
+import org.netbeans.modules.nativeimage.spi.debug.filters.VariableDisplayer;
+import org.openide.util.Exceptions;
+import org.openide.util.NbBundle;
+
+/**
+ * Representation of a native image debugger.
+ * @since 1.0
+ */
+public final class NIDebugger {
+
+ private final NIDebuggerProvider provider;
+
+ NIDebugger(NIDebuggerProvider provider) {
+ this.provider = provider;
+ }
+
+ /**
+ * Creates a builder of a new debugger instance.
+ *
+ * @return a builder of a new debugger instance
+ * @throws IllegalStateException when the native debugger is not available
+ * (there is not an implementation of {@link NIDebuggerServiceProvider}
+ * registered in the default lookup).
+ * @since 1.0
+ */
+ @NbBundle.Messages({"MSG_NoNativeDebug=No native debugger is available. Please install native debugger module."})
+ public static Builder newBuilder() throws IllegalStateException {
+ NIDebuggerServiceProvider provider = Lookup.getDefault().lookup(NIDebuggerServiceProvider.class);
+ if (provider == null) {
+ throw Exceptions.attachLocalizedMessage(new IllegalStateException(), Bundle.MSG_NoNativeDebug());
+ } else {
+ return new Builder(provider.create());
+ }
+ }
+
+ /**
+ * Add or change a line breakpoint into the debugger.
+ * A breakpoint is added when the `id` is used for the first time and modified
+ * when breakpoint with that `id` was added already.
+ *
+ * @param id a unique ID of the breakpoint
+ * @param breakpointDescriptor the breakpoint descriptor
+ * @return an instance of the native breakpoint
+ * @since 1.0
+ */
+ public Breakpoint addLineBreakpoint(Object id, NILineBreakpointDescriptor breakpointDescriptor) {
+ Breakpoint breakpoint = provider.addLineBreakpoint(id, breakpointDescriptor);
+ assert breakpoint != null;
+ return breakpoint;
+ }
+
+ /**
+ * Remove breakpoint with the given id.
+ *
+ * @param id the ID of the breakpoint to remove
+ * @since 1.0
+ */
+ public void removeBreakpoint(Object id) {
+ provider.removeBreakpoint(id);
+ }
+
+ /**
+ * Start the actual debugging session. Call this typically after breakpoints are added.
+ *
+ * @param command a command to run the native image
+ * @param workingDirectory working directory
+ * @param debugger the native debugger command
+ * @param displayName display name of the debugger task
+ * @param executionDescriptor execution descriptor that describes the runtime attributes
+ * @param startedEngine the corresponding DebuggerEngine is passed to this consumer
+ * @return future that completes on the execution finish
+ * @since 1.0
+ */
+ public CompletableFuture<Void> start(List<String> command, File workingDirectory, String debugger, String displayName, ExecutionDescriptor executionDescriptor, Consumer<DebuggerEngine> startedEngine) {
+ return provider.start(command, workingDirectory, debugger, displayName, executionDescriptor, startedEngine);
+ }
+
+ /**
+ * An asynchronous expression evaluation.
+ *
+ * @param expression the expression to evaluate
+ * @param resultName preferred name of the result variable,
+ * when <code>null</code> the expression is used as the name
+ * @param frame the frame to evaluate at
+ * @return the completable future with the evaluation result
+ * @since 1.0
+ */
+ public CompletableFuture<NIVariable> evaluateAsync(String expression, String resultName, NIFrame frame) {
+ return provider.evaluateAsync(expression, resultName, frame);
+ }
+
+ /**
+ * A synchronous expression evaluation. Delegates to the asynchronous evaluation
+ * and wait for it's result.
+ *
+ * @param expression the expression to evaluate
+ * @param resultName preferred name of the result variable,
+ * when <code>null</code> the expression is used as the name
+ * @param frame the frame to evaluate at
+ * @return the evaluation result
+ * @throws EvaluateException when evaluation fails
+ * @since 1.0
+ */
+ public NIVariable evaluate(String expression, String resultName, NIFrame frame) throws EvaluateException {
+ try {
+ return provider.evaluateAsync(expression, resultName, frame).get();
+ } catch (ExecutionException | InterruptedException ex) {
+ throw new EvaluateException(ex.getCause());
+ }
+ }
+
+ /**
+ * Read data from memory.
+ *
+ * @param address address where to read the data from
+ * @param offset offset relative to the address where to start reading
+ * @param length number of bytes to read
+ * @return hexadecimal representation of the memory content, or <code>null</code>
+ * when the read is not successful
+ * @since 1.0
+ */
+ public String readMemory(String address, long offset, int length) {
+ return provider.readMemory(address, offset, length);
+ }
+
+ /**
+ * Get version of the underlying native debugger.
+ *
+ * @since 1.0
+ */
+ public String getVersion() {
+ return provider.getVersion();
+ }
+
+ /**
+ * A builder that creates a Native Image debugger with optional displayers.
+ *
+ * @since 1.0
+ */
+ public static final class Builder {
+
+ private final NIDebuggerProvider debuggerProvider;
+
+ Builder(NIDebuggerProvider debuggerProvider) {
+ this.debuggerProvider = debuggerProvider;
+ }
+
+ /**
+ * Displayer of native frames.
+ *
+ * @param frameDisplayer translator of the native frame to it's displayed information
+ * @since 1.0
+ */
+ public Builder frameDisplayer(FrameDisplayer frameDisplayer) {
+ this.debuggerProvider.setFrameDisplayer(frameDisplayer);
+ return this;
+ }
+
+ /**
+ * Displayer of native variables.
+ *
+ * @param variablesDisplayer translator of native variables to displayed variables.
+ * @since 1.0
+ */
+ public Builder variablesDisplayer(VariableDisplayer variablesDisplayer) {
+ this.debuggerProvider.setVariablesDisplayer(variablesDisplayer);
+ return this;
+ }
+
+ /**
+ * Create the debugger instance.
+ * @since 1.0
+ */
+ public NIDebugger build() {
+ return new NIDebugger(debuggerProvider);
+ }
+ }
+}
diff --git a/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/NIFrame.java b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/NIFrame.java
new file mode 100644
index 0000000..4ffc48c
--- /dev/null
+++ b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/NIFrame.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.nativeimage.api.debug;
+
+/**
+ * Representation of a native stack frame.
+ *
+ * @since 1.0
+ */
+public interface NIFrame {
+
+ /**
+ * Frame's thread ID.
+ * @since 1.0
+ */
+ String getThreadId();
+
+ /**
+ * Frame's depth level. The top frame has level 0.
+ * @since 1.0
+ */
+ int getLevel();
+
+ /**
+ * Frame's native address.
+ * @since 1.0
+ */
+ String getAddress();
+
+ /**
+ * A short name of the file associated with the frame.
+ * @since 1.0
+ */
+ String getShortFileName();
+
+ /**
+ * A full name of the file associated with the frame.
+ * @since 1.0
+ */
+ String getFullFileName();
+
+ /**
+ * Name of the function associated with the frame.
+ * @since 1.0
+ */
+ String getFunctionName();
+
+ /**
+ * 1-based line of the frame location.
+ * @since 1.0
+ */
+ int getLine();
+}
diff --git a/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/NILineBreakpointDescriptor.java b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/NILineBreakpointDescriptor.java
new file mode 100644
index 0000000..192be78
--- /dev/null
+++ b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/NILineBreakpointDescriptor.java
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.nativeimage.api.debug;
+
+import org.netbeans.api.annotations.common.CheckForNull;
+
+/**
+ * Description of a line native breakpoint.
+ *
+ * @since 1.0
+ */
+public final class NILineBreakpointDescriptor {
+
+ private final String filePath;
+ private final int line;
+ private final boolean enabled;
+ private final String condition;
+ private final boolean hidden;
+
+ private NILineBreakpointDescriptor(String filePath, int line, boolean enabled, String condition, boolean hidden) {
+ this.filePath = filePath;
+ this.line = line;
+ this.enabled = enabled;
+ this.condition = condition;
+ this.hidden = hidden;
+ }
+
+ /**
+ * Create a new line native breakpoint builder.
+ *
+ * @param filePath file path of the breakpoint
+ * @param lineNumber 1-based line number
+ * @since 1.0
+ */
+ public static Builder newBuilder(String filePath, int lineNumber) {
+ return new Builder(filePath, lineNumber);
+ }
+
+ /**
+ * Get path of the file.
+ *
+ * @since 1.0
+ */
+ public String getFilePath() {
+ return filePath;
+ }
+
+ /**
+ * Get 1-based line number.
+ *
+ * @since 1.0
+ */
+ public int getLine() {
+ return line;
+ }
+
+ /**
+ * Check if the breakpoint is to be enabled.
+ *
+ * @since 1.0
+ */
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ /**
+ * Get the breakpoint condition.
+ *
+ * @return the condition, or <code>null</code> when the breakpoint does not have any condition.
+ * @since 1.0
+ */
+ @CheckForNull
+ public String getCondition() {
+ return condition;
+ }
+
+ /**
+ * Check if the breakpoint is to be hidden (not user-visible).
+ *
+ * @since 1.0
+ */
+ public boolean isHidden() {
+ return hidden;
+ }
+
+ /**
+ * Builder of a line native breakpoint descriptor. The builder is reusable
+ * and the built breakpoint descriptor can be used to update existing breakpoints.
+ *
+ * @since 1.0
+ */
+ public static final class Builder {
+
+ private String filePath;
+ private int line;
+ private boolean enabled = true;
+ private String condition;
+ private boolean hidden = false;
+
+ Builder(String filePath, int lineNumber) {
+ this.filePath = filePath;
+ this.line = lineNumber;
+ }
+
+ /**
+ * Set a file path.
+ *
+ * @since 1.0
+ */
+ public Builder filePath(String filePath) {
+ this.filePath = filePath;
+ return this;
+ }
+
+ /**
+ * Set a 1-based line number.
+ *
+ * @since 1.0
+ */
+ public Builder line(int lineNumber) {
+ this.line = lineNumber;
+ return this;
+ }
+
+ /**
+ * Set a condition.
+ *
+ * @since 1.0
+ */
+ public Builder condition(String condition) {
+ this.condition = condition;
+ return this;
+ }
+
+ /**
+ * Set an enabled state of the breakpoint. The breakpoint is enabled by default.
+ *
+ * @since 1.0
+ */
+ public Builder enabled(boolean enabled) {
+ this.enabled = enabled;
+ return this;
+ }
+
+ /**
+ * Set a hidden state of the breakpoint. Hidden breakpoints are not visible
+ * to users. The breakpoint is not hidden by default.
+ *
+ * @since 1.0
+ */
+ public Builder hidden(boolean hidden) {
+ this.hidden = hidden;
+ return this;
+ }
+
+ /**
+ * Build the line breakpoint descriptor.
+ */
+ public NILineBreakpointDescriptor build() {
+ return new NILineBreakpointDescriptor(filePath, line, enabled, condition, hidden);
+ }
+ }
+}
diff --git a/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/NIVariable.java b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/NIVariable.java
new file mode 100644
index 0000000..cd46e7c
--- /dev/null
+++ b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/NIVariable.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.nativeimage.api.debug;
+
+/**
+ * Representation of a native variable.
+ * @since 1.0
+ */
+public interface NIVariable {
+
+ /**
+ * Name of the variable.
+ *
+ * @since 1.0
+ */
+ String getName();
+
+ /**
+ * Type of the variable value.
+ *
+ * @since 1.0
+ */
+ String getType();
+
+ /**
+ * String representation of the variable value.
+ *
+ * @since 1.0
+ */
+ String getValue();
+
+ /**
+ * The parent variable, if any. Every child variable has a corresponding parent
+ * variable.
+ *
+ * @return the parent variable, or <code>null</code>.
+ * @since 1.0
+ */
+ NIVariable getParent();
+
+ /**
+ * Number of child variables (properties, or array elements) of this variable.
+ *
+ * @since 1.0
+ */
+ int getNumChildren();
+
+ /**
+ * Get the child variables in the specified index range. Children starting at
+ * <code>from</code> index and up to and excluding <code>to</code> index will
+ * be returned. If <code>from</code> is less than zero, all children are returned.
+ *
+ * @since 1.0
+ */
+ NIVariable[] getChildren(int from, int to);
+
+ /**
+ * Get all variable's children.
+ *
+ * @since 1.0
+ */
+ default NIVariable[] getChildren() {
+ return getChildren(0, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Get the full expression that this variable object represents.
+ *
+ * @since 1.0
+ */
+ String getExpressionPath();
+
+ /**
+ * Get the frame this variable is associated with.
+ *
+ * @return the frame, or <code>null</code>.
+ * @since 1.0
+ */
+ NIFrame getFrame();
+}
diff --git a/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/spi/debug/NIDebuggerProvider.java b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/spi/debug/NIDebuggerProvider.java
new file mode 100644
index 0000000..c2ff425
--- /dev/null
+++ b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/spi/debug/NIDebuggerProvider.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.nativeimage.spi.debug;
+
+import java.io.File;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import org.netbeans.api.debugger.Breakpoint;
+import org.netbeans.api.debugger.DebuggerEngine;
+
+import org.netbeans.api.extexecution.ExecutionDescriptor;
+import org.netbeans.modules.nativeimage.api.debug.NIFrame;
+import org.netbeans.modules.nativeimage.api.debug.NILineBreakpointDescriptor;
+import org.netbeans.modules.nativeimage.api.debug.NIVariable;
+import org.netbeans.modules.nativeimage.spi.debug.filters.FrameDisplayer;
+import org.netbeans.modules.nativeimage.spi.debug.filters.VariableDisplayer;
+
+/**
+ * Provider of the native image debugger.
+ *
+ * @author martin
+ * @since 1.0
+ */
+public interface NIDebuggerProvider {
+
+ /**
+ * Add or change a line breakpoint into the debugger.
+ * A breakpoint is added when the `id` is used for the first time and modified
+ * when breakpoint with that `id` was added already.
+ *
+ * @param id a unique ID of the breakpoint
+ * @param breakpointDescriptor the breakpoint descriptor
+ * @return an instance of the native breakpoint
+ * @since 1.0
+ */
+ Breakpoint addLineBreakpoint(Object id, NILineBreakpointDescriptor breakpointDescriptor);
+
+ /**
+ * Remove breakpoint with the given id.
+ *
+ * @param id the ID of the breakpoint to remove
+ * @since 1.0
+ */
+ void removeBreakpoint(Object id);
+
+ /**
+ * Set a displayer of native frames.
+ *
+ * @param frameDisplayer translator of the native frame to it's displayed information
+ * @since 1.0
+ */
+ void setFrameDisplayer(FrameDisplayer frameDisplayer);
+
+ /**
+ * Set a displayer of native variables.
+ *
+ * @param variablesDisplayer translator of native variables to displayed variables.
+ * @since 1.0
+ */
+ void setVariablesDisplayer(VariableDisplayer variablesDisplayer);
+
+ /**
+ * Start the actual debugging session. Called typically after breakpoints are added.
+ *
+ * @param command a command to run the native image
+ * @param workingDirectory working directory
+ * @param debugger the native debugger command
+ * @param displayName display name of the debugger task
+ * @param executionDescriptor execution descriptor that describes the runtime attributes
+ * @param startedEngine the corresponding DebuggerEngine is passed to this consumer
+ * @param finishedCallback notification of the execution finish
+ * @since 1.0
+ */
+ CompletableFuture<Void> start(List<String> command, File workingDirectory, String debugger, String displayName, ExecutionDescriptor executionDescriptor, Consumer<DebuggerEngine> startedEngine);
+
+ /**
+ * An asynchronous expression evaluation.
+ *
+ * @param expression the expression to evaluate
+ * @param resultName preferred name of the result variable,
+ * when <code>null</code> the expression is used as the name
+ * @param frame the frame to evaluate at
+ * @return the completable future with the evaluation result
+ * @since 1.0
+ */
+ CompletableFuture<NIVariable> evaluateAsync(String expression, String resultName, NIFrame frame);
+
+ /**
+ * Read data from memory.
+ *
+ * @param address address where to read the data from
+ * @param offset offset relative to the address where to start reading
+ * @param length number of bytes to read
+ * @return hexadecimal representation of the memory content, or <code>null</code>
+ * when the read is not successful
+ * @since 1.0
+ */
+ String readMemory(String address, long offset, int length);
+
+ /**
+ * Get version of the underlying native debugger.
+ *
+ * @since 1.0
+ */
+ String getVersion();
+}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/spi/debug/NIDebuggerServiceProvider.java
similarity index 72%
copy from cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java
copy to ide/nativeimage.api/src/org/netbeans/modules/nativeimage/spi/debug/NIDebuggerServiceProvider.java
index 0fc9c76..37ec9fe 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java
+++ b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/spi/debug/NIDebuggerServiceProvider.java
@@ -16,17 +16,17 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.netbeans.modules.cpplite.debugger;
+package org.netbeans.modules.nativeimage.spi.debug;
-public final class EvaluateException extends Exception {
+/**
+ * Provider of the native image debugger.
+ * @since 1.0
+ */
+public interface NIDebuggerServiceProvider {
/**
- * Constructs an instance of <code>EvaluateException</code> with the
- * specified detail message.
- *
- * @param msg the detail message.
+ * Create a new instance of the debugger provider.
+ * @since 1.0
*/
- EvaluateException(String msg) {
- super(msg);
- }
+ NIDebuggerProvider create();
}
diff --git a/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/spi/debug/filters/FrameDisplayer.java b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/spi/debug/filters/FrameDisplayer.java
new file mode 100644
index 0000000..91d92cc
--- /dev/null
+++ b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/spi/debug/filters/FrameDisplayer.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.nativeimage.spi.debug.filters;
+
+import java.net.URI;
+import java.util.function.Supplier;
+import org.netbeans.api.annotations.common.CheckForNull;
+
+import org.netbeans.modules.nativeimage.api.debug.NIFrame;
+
+/**
+ * Displayer of stack frames. Modifies the way how frames are presented.
+ *
+ * @since 1.0
+ */
+public interface FrameDisplayer {
+
+ /**
+ * Provide display information of a stack frame.
+ *
+ * @param frame the stack frame
+ * @return a display information, or <code>null</code> to skip this frame.
+ * @since 1.0
+ */
+ DisplayedFrame displayed(NIFrame frame);
+
+ /**
+ * Display information of a frame.
+ * @since 1.0
+ */
+ public static final class DisplayedFrame {
+
+ private final String displayName;
+ private final String description;
+ private final int line;
+ private final Supplier<URI> uriSupplier;
+
+ private DisplayedFrame(String displayName, String description, int line, Supplier<URI> uriSupplier) {
+ this.displayName = displayName;
+ this.description = description;
+ this.line = line;
+ this.uriSupplier = uriSupplier;
+ }
+
+ /**
+ * Creates a new builder with a user visible display name of the frame.
+ *
+ * @since 1.0
+ */
+ public static Builder newBuilder(String displayName) {
+ return new Builder(displayName);
+ }
+
+ /**
+ * Get a display name of the frame.
+ *
+ * @since 1.0
+ */
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ /**
+ * Get a description of the frame.
+ *
+ * @since 1.0
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Get a 1-based line number of the frame.
+ *
+ * @since 1.0
+ */
+ public int getLine() {
+ return line;
+ }
+
+ /**
+ * Get URI of the source file associated with the frame.
+ *
+ * @return the URI, or <code>null</code> when unknown.
+ * @since 1.0
+ */
+ @CheckForNull
+ public URI getSourceURI() {
+ if (uriSupplier != null) {
+ return uriSupplier.get();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Builder of the {@link DisplayedFrame}.
+ * @since 1.0
+ */
+ public static final class Builder {
+
+ private final String displayName;
+ private String description;
+ private int line;
+ private Supplier<URI> uriSupplier;
+
+ Builder(String displayName) {
+ this.displayName = displayName;
+ }
+
+ /**
+ * Set frame description.
+ *
+ * @since 1.0
+ */
+ public Builder description(String description) {
+ this.description = description;
+ return this;
+ }
+
+ /**
+ * 1-based line number information of the frame location.
+ *
+ * @since 1.0
+ */
+ public Builder line(int lineNumber) {
+ this.line = lineNumber;
+ return this;
+ }
+
+ /**
+ * URI of the source file associated with the frame.
+ * @since 1.0
+ */
+ public Builder sourceURISupplier(Supplier<URI> uriSupplier) {
+ this.uriSupplier = uriSupplier;
+ return this;
+ }
+
+ /**
+ * Build the {@link DisplayedFrame}.
+ *
+ * @since 1.0
+ */
+ public DisplayedFrame build() {
+ return new DisplayedFrame(displayName, description, line, uriSupplier);
+ }
+ }
+ }
+}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/spi/debug/filters/VariableDisplayer.java
similarity index 64%
copy from cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java
copy to ide/nativeimage.api/src/org/netbeans/modules/nativeimage/spi/debug/filters/VariableDisplayer.java
index 0fc9c76..9d6cfa1 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java
+++ b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/spi/debug/filters/VariableDisplayer.java
@@ -16,17 +16,22 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.netbeans.modules.cpplite.debugger;
+package org.netbeans.modules.nativeimage.spi.debug.filters;
-public final class EvaluateException extends Exception {
+import org.netbeans.modules.nativeimage.api.debug.NIVariable;
+
+/**
+ * Displayer of variables. Modifies the way how variables are presented.
+ *
+ * @since 1.0
+ */
+public interface VariableDisplayer {
/**
- * Constructs an instance of <code>EvaluateException</code> with the
- * specified detail message.
- *
- * @param msg the detail message.
+ * Translate a list of original native variables into a list of variables
+ * presented to the debugger user.
+ * @since 1.0
*/
- EvaluateException(String msg) {
- super(msg);
- }
+ NIVariable[] displayed(NIVariable... variables);
+
}
diff --git a/ide/nativeimage.api/test/unit/src/org/netbeans/modules/nativeimage/debug/NIDebuggerServiceTest.java b/ide/nativeimage.api/test/unit/src/org/netbeans/modules/nativeimage/debug/NIDebuggerServiceTest.java
new file mode 100644
index 0000000..f7ad3dd
--- /dev/null
+++ b/ide/nativeimage.api/test/unit/src/org/netbeans/modules/nativeimage/debug/NIDebuggerServiceTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.nativeimage.debug;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.concurrent.CompletableFuture;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+
+import org.netbeans.modules.nativeimage.api.debug.NIDebugger;
+import org.netbeans.modules.nativeimage.api.debug.NILineBreakpointDescriptor;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+import org.openide.util.lookup.ProxyLookup;
+
+public class NIDebuggerServiceTest {
+
+ public NIDebuggerServiceTest() {
+ }
+
+ private static Lookup getTestLookup(String checkStartParams) {
+ Lookup launchCtx = new ProxyLookup(
+ Lookups.fixed(new TestNIDebuggerServiceProvider(checkStartParams)),
+ Lookup.getDefault()
+ );
+ return launchCtx;
+ }
+
+ @Test
+ public void testFindServiceProvider() {
+ Lookups.executeWith(getTestLookup(""), () -> {
+ NIDebugger debugger = NIDebugger.newBuilder().build();
+ assertNotNull("Test NI debugger service is not available.", debugger);
+ });
+ }
+
+ @Test
+ public void testDebuggerProvider() {
+ String checkStartParams = "[CMD1, CMD2]WDMIDdisplayNamenull{ID1=TEST ID1filePath110truecondition1false}nullnull";
+ Lookups.executeWith(getTestLookup(checkStartParams), () -> {
+ NIDebugger debugger = NIDebugger.newBuilder().build();
+ debugger.addLineBreakpoint("ID1", NILineBreakpointDescriptor.newBuilder("filePath1", 10).enabled(true).condition("condition1").hidden(false).build());
+ debugger.addLineBreakpoint("ID2", NILineBreakpointDescriptor.newBuilder("filePath2", 20).enabled(false).condition("condition2").hidden(true).build());
+ debugger.removeBreakpoint("ID2");
+ CompletableFuture<Void> completed = debugger.start(Arrays.asList("CMD1", "CMD2"), new File("WD"), "MID", "displayName", null, engine -> {});
+ assertTrue(completed.isDone());
+ });
+ }
+}
diff --git a/ide/nativeimage.api/test/unit/src/org/netbeans/modules/nativeimage/debug/TestNIDebuggerProvider.java b/ide/nativeimage.api/test/unit/src/org/netbeans/modules/nativeimage/debug/TestNIDebuggerProvider.java
new file mode 100644
index 0000000..309b859
--- /dev/null
+++ b/ide/nativeimage.api/test/unit/src/org/netbeans/modules/nativeimage/debug/TestNIDebuggerProvider.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.nativeimage.debug;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import static org.junit.Assert.assertEquals;
+import org.netbeans.api.debugger.Breakpoint;
+import org.netbeans.api.debugger.DebuggerEngine;
+
+import org.netbeans.api.extexecution.ExecutionDescriptor;
+import org.netbeans.modules.nativeimage.api.debug.NIFrame;
+import org.netbeans.modules.nativeimage.api.debug.NILineBreakpointDescriptor;
+import org.netbeans.modules.nativeimage.api.debug.NIVariable;
+import org.netbeans.modules.nativeimage.spi.debug.NIDebuggerProvider;
+import org.netbeans.modules.nativeimage.spi.debug.filters.FrameDisplayer;
+import org.netbeans.modules.nativeimage.spi.debug.filters.VariableDisplayer;
+
+public class TestNIDebuggerProvider implements NIDebuggerProvider {
+
+ private final Map<Object, String> breakpoints = new HashMap<>();
+ private final String checkStartParams;
+ private FrameDisplayer frameDisplayer;
+ private VariableDisplayer variablesDisplayer;
+
+ public TestNIDebuggerProvider(String checkStartParams) {
+ this.checkStartParams = checkStartParams;
+ }
+
+ @Override
+ public Breakpoint addLineBreakpoint(Object id, NILineBreakpointDescriptor bd) {
+ String testBP = id + bd.getFilePath() + bd.getLine() + bd.isEnabled() + bd.getCondition() + bd.isHidden();
+ breakpoints.put(id, testBP);
+ return new Breakpoint() {
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+ @Override
+ public void disable() {}
+ @Override
+ public void enable() {}
+ };
+ }
+
+ @Override
+ public void removeBreakpoint(Object id) {
+ breakpoints.remove(id);
+ }
+
+ @Override
+ public void setFrameDisplayer(FrameDisplayer frameDisplayer) {
+ this.frameDisplayer = frameDisplayer;
+ }
+
+ @Override
+ public void setVariablesDisplayer(VariableDisplayer variablesDisplayer) {
+ this.variablesDisplayer = variablesDisplayer;
+ }
+
+ @Override
+ public CompletableFuture<Void> start(List<String> command, File workingDirectory, String debugger, String displayName, ExecutionDescriptor executionDescriptor, Consumer<DebuggerEngine> startedEngine) {
+ assertEquals(checkStartParams, command.toString() + workingDirectory + debugger + displayName + executionDescriptor + breakpoints.toString() + frameDisplayer + variablesDisplayer);
+ startedEngine.accept(null);
+ return CompletableFuture.completedFuture(null);
+ }
+
+ @Override
+ public CompletableFuture<NIVariable> evaluateAsync(String expression, String resultName, NIFrame frame) {
+ return CompletableFuture.completedFuture(null);
+ }
+
+ @Override
+ public String readMemory(String address, long offset, int length) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public String getVersion() {
+ return "Test_NI";
+ }
+
+}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java b/ide/nativeimage.api/test/unit/src/org/netbeans/modules/nativeimage/debug/TestNIDebuggerServiceProvider.java
similarity index 59%
copy from cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java
copy to ide/nativeimage.api/test/unit/src/org/netbeans/modules/nativeimage/debug/TestNIDebuggerServiceProvider.java
index 0fc9c76..7a16f19 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java
+++ b/ide/nativeimage.api/test/unit/src/org/netbeans/modules/nativeimage/debug/TestNIDebuggerServiceProvider.java
@@ -16,17 +16,22 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.netbeans.modules.cpplite.debugger;
+package org.netbeans.modules.nativeimage.debug;
-public final class EvaluateException extends Exception {
+import org.netbeans.modules.nativeimage.spi.debug.NIDebuggerProvider;
+import org.netbeans.modules.nativeimage.spi.debug.NIDebuggerServiceProvider;
- /**
- * Constructs an instance of <code>EvaluateException</code> with the
- * specified detail message.
- *
- * @param msg the detail message.
- */
- EvaluateException(String msg) {
- super(msg);
+public class TestNIDebuggerServiceProvider implements NIDebuggerServiceProvider {
+
+ private final String checkStartParams;
+
+ public TestNIDebuggerServiceProvider(String checkStartParams) {
+ this.checkStartParams = checkStartParams;
}
+
+ @Override
+ public NIDebuggerProvider create() {
+ return new TestNIDebuggerProvider(checkStartParams);
+ }
+
}
diff --git a/java/java.kit/nbproject/project.xml b/java/java.kit/nbproject/project.xml
index 51b43fc..607df4c 100644
--- a/java/java.kit/nbproject/project.xml
+++ b/java/java.kit/nbproject/project.xml
@@ -167,6 +167,13 @@
</run-dependency>
</dependency>
<dependency>
+ <code-name-base>org.netbeans.modules.java.nativeimage.debugger</code-name-base>
+ <run-dependency>
+ <release-version>0</release-version>
+ <specification-version>0.1</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
<code-name-base>org.netbeans.modules.java.navigation</code-name-base>
<run-dependency>
<release-version>1</release-version>
diff --git a/java/java.lsp.server/nbcode/nbproject/platform.properties b/java/java.lsp.server/nbcode/nbproject/platform.properties
index a4903f4..9e0f111 100644
--- a/java/java.lsp.server/nbcode/nbproject/platform.properties
+++ b/java/java.lsp.server/nbcode/nbproject/platform.properties
@@ -17,6 +17,7 @@
branding.token=nbcode
cluster.path=\
+ ${nbplatform.active.dir}/cpplite:\
${nbplatform.active.dir}/enterprise:\
${nbplatform.active.dir}/extide:\
${nbplatform.active.dir}/ide:\
@@ -30,8 +31,6 @@ disabled.modules=\
bcprov,\
com.google.guava,\
com.googlecode.javaewah.JavaEWAH,\
- com.jcraft.jsch,\
- com.jcraft.jzlib,\
libs.c.kohlschutter.junixsocket,\
org.apache.commons.httpclient,\
org.apache.commons.lang,\
@@ -110,6 +109,9 @@ disabled.modules=\
org.netbeans.modules.cordova.platforms,\
org.netbeans.modules.cordova.platforms.android,\
org.netbeans.modules.core.kit,\
+ org.netbeans.modules.cpplite.editor,\
+ org.netbeans.modules.cpplite.kit,\
+ org.netbeans.modules.cpplite.project,\
org.netbeans.modules.css.editor,\
org.netbeans.modules.css.model,\
org.netbeans.modules.css.prep,\
@@ -132,7 +134,6 @@ disabled.modules=\
org.netbeans.modules.debugger.jpda.kit,\
org.netbeans.modules.debugger.jpda.visual,\
org.netbeans.modules.derby,\
- org.netbeans.modules.dlight.nativeexecution,\
org.netbeans.modules.dlight.nativeexecution.nb,\
org.netbeans.modules.dlight.terminal,\
org.netbeans.modules.docker.api,\
@@ -300,7 +301,6 @@ disabled.modules=\
org.netbeans.modules.team.commons,\
org.netbeans.modules.team.ide,\
org.netbeans.modules.templates,\
- org.netbeans.modules.terminal,\
org.netbeans.modules.terminal.nb,\
org.netbeans.modules.testng.ant,\
org.netbeans.modules.testng.maven,\
diff --git a/java/java.lsp.server/nbproject/project.xml b/java/java.lsp.server/nbproject/project.xml
index d78ddd8..eb90897 100644
--- a/java/java.lsp.server/nbproject/project.xml
+++ b/java/java.lsp.server/nbproject/project.xml
@@ -321,6 +321,24 @@
</run-dependency>
</dependency>
<dependency>
+ <code-name-base>org.netbeans.modules.nativeimage.api</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>0</release-version>
+ <specification-version>0.1</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.netbeans.modules.java.nativeimage.debugger</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>0</release-version>
+ <specification-version>0.1</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
<code-name-base>org.netbeans.modules.parsing.api</code-name-base>
<build-prerequisite/>
<compile-dependency/>
diff --git a/java/java.lsp.server/script/etc/nbcode.clusters b/java/java.lsp.server/script/etc/nbcode.clusters
index 2151943..9a5a263 100644
--- a/java/java.lsp.server/script/etc/nbcode.clusters
+++ b/java/java.lsp.server/script/etc/nbcode.clusters
@@ -3,6 +3,7 @@ ide
extide
webcommon
java
+cpplite
extra
enterprise
nbcode
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java
index 6b274d2..4541ed3 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java
@@ -29,6 +29,8 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.lsp4j.debug.Capabilities;
@@ -69,6 +71,7 @@ import org.eclipse.lsp4j.debug.services.IDebugProtocolServer;
import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode;
import org.netbeans.api.debugger.ActionsManager;
import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.Session;
import org.netbeans.api.debugger.jpda.InvalidExpressionException;
import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.api.debugger.jpda.ObjectVariable;
@@ -80,6 +83,9 @@ import org.netbeans.modules.java.lsp.server.debugging.launch.NbLaunchRequestHand
import org.netbeans.modules.java.lsp.server.debugging.breakpoints.NbBreakpointsRequestHandler;
import org.netbeans.modules.java.lsp.server.debugging.variables.NbVariablesRequestHandler;
import org.netbeans.modules.java.lsp.server.debugging.utils.ErrorUtilities;
+import org.netbeans.modules.nativeimage.api.debug.EvaluateException;
+import org.netbeans.modules.nativeimage.api.debug.NIDebugger;
+import org.netbeans.modules.nativeimage.api.debug.NIVariable;
import org.netbeans.spi.debugger.ui.DebuggingView.DVFrame;
import org.netbeans.spi.debugger.ui.DebuggingView.DVThread;
@@ -187,8 +193,8 @@ public final class NbProtocolServer implements IDebugProtocolServer {
}
response.setAllThreadsContinued(false);
} else {
- JPDADebugger debugger = context.getDebugSession().getDebugger();
- debugger.getSession().getCurrentEngine().getActionsManager().doAction("continue");
+ Session session = context.getDebugSession().getSession();
+ session.getCurrentEngine().getActionsManager().doAction("continue");
context.getThreadsProvider().getThreadObjects().cleanAll();
response.setAllThreadsContinued(true);
}
@@ -249,8 +255,8 @@ public final class NbProtocolServer implements IDebugProtocolServer {
ev = null;
}
} else {
- JPDADebugger debugger = context.getDebugSession().getDebugger();
- debugger.getSession().getCurrentEngine().getActionsManager().doAction("pause");
+ Session session = context.getDebugSession().getSession();
+ session.getCurrentEngine().getActionsManager().doAction("pause");
ev = new StoppedEventArguments();
ev.setReason("pause");
ev.setThreadId(0);
@@ -417,48 +423,78 @@ public final class NbProtocolServer implements IDebugProtocolServer {
stackFrame.getDVFrame().makeCurrent(); // The evaluation is always performed with respect to the current frame
DVThread dvThread = stackFrame.getDVFrame().getThread();
int threadId = context.getThreadsProvider().getId(dvThread);
- JPDADebugger debugger = context.getDebugSession().getDebugger();
- Variable variable;
- try {
- variable = debugger.evaluate(expression);
- } catch (InvalidExpressionException ex) {
- throw ErrorUtilities.createResponseErrorException(
- ex.getLocalizedMessage(),
- ResponseErrorCode.ParseError);
- }
EvaluateResponse response = new EvaluateResponse();
- TruffleVariable truffleVariable = TruffleVariable.get(variable);
- if (truffleVariable != null) {
- int referenceId = context.getThreadsProvider().getThreadObjects().addObject(threadId, truffleVariable);
- response.setResult(truffleVariable.getDisplayValue());
- response.setVariablesReference(referenceId);
- response.setType(truffleVariable.getType());
- response.setIndexedVariables(truffleVariable.isLeaf() ? 0 : truffleVariable.getChildren().length);
+ JPDADebugger debugger = context.getDebugSession().getJPDADebugger();
+ if (debugger != null) {
+ evaluateJPDA(debugger, expression, threadId, response);
} else {
- if (variable instanceof ObjectVariable) {
- int referenceId = context.getThreadsProvider().getThreadObjects().addObject(threadId, variable);
- int indexedVariables = ((ObjectVariable) variable).getFieldsCount();
- String toString;
- try {
- toString = ((ObjectVariable) variable).getToStringValue();
- } catch (InvalidExpressionException ex) {
- toString = variable.getValue();
- }
- response.setResult(toString);
- response.setVariablesReference(referenceId);
- response.setType(variable.getType());
- response.setIndexedVariables(Math.max(indexedVariables, 0));
- } else {
- response.setResult(variable.getValue());
- response.setVariablesReference(0);
- response.setType(variable.getType());
- response.setIndexedVariables(0);
- }
+ NIDebugger niDebugger = context.getDebugSession().getNIDebugger();
+ evaluateNative(niDebugger, expression, threadId, response);
}
return response;
});
}
+ private void evaluateJPDA(JPDADebugger debugger, String expression, int threadId, EvaluateResponse response) {
+ Variable variable;
+ try {
+ variable = debugger.evaluate(expression);
+ } catch (InvalidExpressionException ex) {
+ throw ErrorUtilities.createResponseErrorException(
+ ex.getLocalizedMessage(),
+ ResponseErrorCode.ParseError);
+ }
+ TruffleVariable truffleVariable = TruffleVariable.get(variable);
+ if (truffleVariable != null) {
+ int referenceId = context.getThreadsProvider().getThreadObjects().addObject(threadId, truffleVariable);
+ response.setResult(truffleVariable.getDisplayValue());
+ response.setVariablesReference(referenceId);
+ response.setType(truffleVariable.getType());
+ response.setIndexedVariables(truffleVariable.isLeaf() ? 0 : truffleVariable.getChildren().length);
+ } else {
+ if (variable instanceof ObjectVariable) {
+ int referenceId = context.getThreadsProvider().getThreadObjects().addObject(threadId, variable);
+ int indexedVariables = ((ObjectVariable) variable).getFieldsCount();
+ String toString;
+ try {
+ toString = ((ObjectVariable) variable).getToStringValue();
+ } catch (InvalidExpressionException ex) {
+ toString = variable.getValue();
+ }
+ response.setResult(toString);
+ response.setVariablesReference(referenceId);
+ response.setType(variable.getType());
+ response.setIndexedVariables(Math.max(indexedVariables, 0));
+ } else {
+ response.setResult(variable.getValue());
+ //response.setVariablesReference(0);
+ response.setType(variable.getType());
+ //response.setIndexedVariables(0);
+ }
+ }
+ }
+
+ private void evaluateNative(NIDebugger niDebugger, String expression, int threadId, EvaluateResponse response) {
+ try {
+ NIVariable variable = niDebugger.evaluate(expression, null, null);
+ int numChildren = variable.getNumChildren();
+ if (numChildren > 0) {
+ int referenceId = context.getThreadsProvider().getThreadObjects().addObject(threadId, variable);
+ response.setResult(variable.getValue());
+ response.setVariablesReference(referenceId);
+ response.setType(variable.getType());
+ response.setIndexedVariables(numChildren);
+ } else {
+ response.setResult(variable.getValue());
+ response.setType(variable.getType());
+ }
+ } catch (EvaluateException ex) {
+ throw ErrorUtilities.createResponseErrorException(
+ ex.getLocalizedMessage(),
+ ResponseErrorCode.ParseError);
+ }
+ }
+
@Override
public CompletableFuture<ExceptionInfoResponse> exceptionInfo(ExceptionInfoArguments args) {
CompletableFuture<ExceptionInfoResponse> future = new CompletableFuture<>();
@@ -466,7 +502,6 @@ public final class NbProtocolServer implements IDebugProtocolServer {
if (exceptionVariable == null) {
ErrorUtilities.completeExceptionally(future, "No exception exists in thread " + args.getThreadId(), ResponseErrorCode.InvalidParams);
} else {
- JPDADebugger debugger = context.getDebugSession().getDebugger();
Throwable exception = (Throwable) exceptionVariable.createMirrorObject();
String typeName = exception.getLocalizedMessage(); // TODO
String exceptionToString = exception.toString();
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbThreads.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbThreads.java
index 4e7e439..96c5f79 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbThreads.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbThreads.java
@@ -55,28 +55,27 @@ public final class NbThreads {
@Override
public void sessionAdded(Session session) {
DebuggerManager.getDebuggerManager().removeDebuggerListener(DebuggerManager.PROP_SESSIONS, this);
- JPDADebugger debugger = session.lookupFirst(null, JPDADebugger.class);
- initThreads(context, debugger);
+ initThreads(context, session);
}
});
}
- private void initThreads(DebugAdapterContext context, JPDADebugger debugger) {
- DebuggerEngine engine = debugger.getSession().getCurrentEngine();
+ private void initThreads(DebugAdapterContext context, Session session) {
+ DebuggerEngine engine = session.getCurrentEngine();
if (engine == null) {
- debugger.getSession().addPropertyChangeListener(Session.PROP_CURRENT_LANGUAGE, new PropertyChangeListener() {
+ session.addPropertyChangeListener(Session.PROP_CURRENT_LANGUAGE, new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
- DebuggerEngine currentEngine = debugger.getSession().getCurrentEngine();
+ DebuggerEngine currentEngine = session.getCurrentEngine();
if (currentEngine != null) {
- debugger.getSession().removePropertyChangeListener(Session.PROP_CURRENT_LANGUAGE, this);
+ session.removePropertyChangeListener(Session.PROP_CURRENT_LANGUAGE, this);
if (!initialized.getAndSet(true)) {
initThreads(context, currentEngine);
}
}
}
});
- engine = debugger.getSession().getCurrentEngine();
+ engine = session.getCurrentEngine();
}
if (engine != null && !initialized.getAndSet(true)) {
initThreads(context, engine);
@@ -209,7 +208,11 @@ public final class NbThreads {
private JPDAThread getJPDAThread(DVThread dvThread) {
// JPDA implementation implements Supplier.
- return ((Supplier<JPDAThread>) dvThread).get();
+ if (dvThread instanceof Supplier) {
+ return ((Supplier<JPDAThread>) dvThread).get();
+ } else {
+ return null;
+ }
}
public void visitThreads(BiConsumer<Integer, DVThread> threadsConsumer) {
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/launch/NbDebugSession.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/launch/NbDebugSession.java
index 1167740..e18052c 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/launch/NbDebugSession.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/launch/NbDebugSession.java
@@ -18,7 +18,9 @@
*/
package org.netbeans.modules.java.lsp.server.debugging.launch;
+import org.netbeans.api.debugger.Session;
import org.netbeans.api.debugger.jpda.JPDADebugger;
+import org.netbeans.modules.nativeimage.api.debug.NIDebugger;
/**
*
@@ -26,14 +28,27 @@ import org.netbeans.api.debugger.jpda.JPDADebugger;
*/
public final class NbDebugSession {
- private final JPDADebugger debugger;
+ private final Session session;
+ private volatile NIDebugger niDebugger;
- NbDebugSession(JPDADebugger debugger) {
- this.debugger = debugger;
+ NbDebugSession(Session session) {
+ this.session = session;
}
- public JPDADebugger getDebugger() {
- return debugger;
+ public Session getSession() {
+ return session;
+ }
+
+ public JPDADebugger getJPDADebugger() {
+ return session.lookupFirst(null, JPDADebugger.class);
+ }
+
+ public NIDebugger getNIDebugger() {
+ return niDebugger;
+ }
+
+ void setNIDebugger(NIDebugger niDebugger) {
+ this.niDebugger = niDebugger;
}
public void detach() {
@@ -41,7 +56,7 @@ public final class NbDebugSession {
}
public void terminate() {
- debugger.getSession().kill();
+ session.kill();
}
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught) {
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/launch/NbLaunchDelegate.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/launch/NbLaunchDelegate.java
index 789a072..a254307 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/launch/NbLaunchDelegate.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/launch/NbLaunchDelegate.java
@@ -20,6 +20,8 @@ package org.netbeans.modules.java.lsp.server.debugging.launch;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -27,6 +29,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import org.eclipse.lsp4j.jsonrpc.ResponseErrorException;
@@ -40,6 +43,8 @@ import org.netbeans.api.debugger.DebuggerManagerAdapter;
import org.netbeans.api.debugger.Session;
import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.api.extexecution.base.ExplicitProcessParameters;
+import org.netbeans.api.extexecution.ExecutionDescriptor;
+import org.netbeans.api.extexecution.ExecutionService;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.queries.UnitTestForSourceQuery;
import org.netbeans.api.project.FileOwnerQuery;
@@ -48,10 +53,13 @@ import org.netbeans.api.project.ProjectUtils;
import org.netbeans.modules.java.lsp.server.Utils;
import org.netbeans.modules.java.lsp.server.debugging.DebugAdapterContext;
import org.netbeans.modules.java.lsp.server.debugging.NbSourceProvider;
+import org.netbeans.modules.java.lsp.server.debugging.utils.ErrorUtilities;
import org.netbeans.modules.java.lsp.server.progress.OperationContext;
import org.netbeans.modules.java.lsp.server.progress.ProgressOperationEvent;
import org.netbeans.modules.java.lsp.server.progress.ProgressOperationListener;
import org.netbeans.modules.java.lsp.server.progress.TestProgressHandler;
+import org.netbeans.modules.java.nativeimage.debugger.api.NIDebugRunner;
+import org.netbeans.modules.nativeimage.api.debug.NIDebugger;
import org.netbeans.spi.project.ActionProgress;
import org.netbeans.spi.project.ActionProvider;
import org.netbeans.spi.project.SingleMethod;
@@ -75,7 +83,7 @@ public abstract class NbLaunchDelegate {
// no op.
}
- public final CompletableFuture<Void> nbLaunch(FileObject toRun, String method, Map<String, Object> launchArguments, DebugAdapterContext context, boolean debug, boolean testRun, Consumer<NbProcessConsole.ConsoleMessage> consoleMessages) {
+ public final CompletableFuture<Void> nbLaunch(FileObject toRun, File nativeImageFile, String method, Map<String, Object> launchArguments, DebugAdapterContext context, boolean debug, boolean testRun, Consumer<NbProcessConsole.ConsoleMessage> consoleMessages) {
CompletableFuture<Void> launchFuture = new CompletableFuture<>();
NbProcessConsole ioContext = new NbProcessConsole(consoleMessages);
SingleMethod singleMethod;
@@ -84,88 +92,161 @@ public abstract class NbLaunchDelegate {
} else {
singleMethod = null;
}
- CompletableFuture<Pair<ActionProvider, String>> commandFuture = findTargetWithPossibleRebuild(toRun, singleMethod, debug, testRun, ioContext);
- commandFuture.thenAccept((providerAndCommand) -> {
- if (debug) {
- DebuggerManager.getDebuggerManager().addDebuggerListener(new DebuggerManagerAdapter() {
- @Override
- public void sessionAdded(Session session) {
- JPDADebugger debugger = session.lookupFirst(null, JPDADebugger.class);
- if (debugger != null) {
- DebuggerManager.getDebuggerManager().removeDebuggerListener(this);
- Map properties = session.lookupFirst(null, Map.class);
- NbSourceProvider sourceProvider = context.getSourceProvider();
- sourceProvider.setSourcePath(properties != null ? (ClassPath) properties.getOrDefault("sourcepath", ClassPath.EMPTY) : ClassPath.EMPTY);
- debugger.addPropertyChangeListener(JPDADebugger.PROP_STATE, new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- int newState = (int) evt.getNewValue();
- if (newState == JPDADebugger.STATE_RUNNING) {
- debugger.removePropertyChangeListener(JPDADebugger.PROP_STATE, this);
- NbDebugSession debugSession = new NbDebugSession(debugger);
- context.setDebugSession(debugSession);
- launchFuture.complete(null);
- context.getConfigurationSemaphore().waitForConfigurationDone();
+ ActionProgress progress = new ActionProgress() {
+ @Override
+ protected void started() {
+ }
+
+ @Override
+ public void finished(boolean success) {
+ ioContext.stop();
+ notifyFinished(context, success);
+ }
+ };
+ if (toRun != null) {
+ CompletableFuture<Pair<ActionProvider, String>> commandFuture = findTargetWithPossibleRebuild(toRun, singleMethod, debug, testRun, ioContext);
+ commandFuture.thenAccept((providerAndCommand) -> {
+ if (debug) {
+ DebuggerManager.getDebuggerManager().addDebuggerListener(new DebuggerManagerAdapter() {
+ @Override
+ public void sessionAdded(Session session) {
+ JPDADebugger debugger = session.lookupFirst(null, JPDADebugger.class);
+ if (debugger != null) {
+ DebuggerManager.getDebuggerManager().removeDebuggerListener(this);
+ Map properties = session.lookupFirst(null, Map.class);
+ NbSourceProvider sourceProvider = context.getSourceProvider();
+ sourceProvider.setSourcePath(properties != null ? (ClassPath) properties.getOrDefault("sourcepath", ClassPath.EMPTY) : ClassPath.EMPTY);
+ debugger.addPropertyChangeListener(JPDADebugger.PROP_STATE, new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ int newState = (int) evt.getNewValue();
+ if (newState == JPDADebugger.STATE_RUNNING) {
+ debugger.removePropertyChangeListener(JPDADebugger.PROP_STATE, this);
+ NbDebugSession debugSession = new NbDebugSession(session);
+ context.setDebugSession(debugSession);
+ launchFuture.complete(null);
+ context.getConfigurationSemaphore().waitForConfigurationDone();
+ }
}
- }
- });
+ });
+ }
}
+ });
+ } else {
+ launchFuture.complete(null);
+ }
+ List<String> args = argsToStringList(launchArguments.get("args"));
+ List<String> vmArgs = argsToStringList(launchArguments.get("vmArgs"));
+ ExplicitProcessParameters params = ExplicitProcessParameters.empty();
+ if (!(args.isEmpty() && vmArgs.isEmpty())) {
+ ExplicitProcessParameters.Builder bld = ExplicitProcessParameters.builder();
+ bld.launcherArgs(vmArgs);
+ bld.args(args);
+ bld.replaceArgs(false);
+ params = bld.build();
+ }
+ OperationContext ctx = OperationContext.find(Lookup.getDefault());
+ ctx.addProgressOperationListener(null, new ProgressOperationListener() {
+ @Override
+ public void progressHandleCreated(ProgressOperationEvent e) {
+ context.setProcessExecutorHandle(e.getProgressHandle());
}
});
- } else {
- launchFuture.complete(null);
- }
- ActionProgress progress = new ActionProgress() {
- @Override
- protected void started() {
- }
+ TestProgressHandler testProgressHandler = ctx.getClient().getNbCodeCapabilities().hasTestResultsSupport() ? new TestProgressHandler(ctx.getClient(), context.getClient(), Utils.toUri(toRun)) : null;
+ Lookup launchCtx = new ProxyLookup(
+ testProgressHandler != null ? Lookups.fixed(toRun, ioContext, progress, testProgressHandler) : Lookups.fixed(toRun, ioContext, progress),
+ Lookup.getDefault()
+ );
- @Override
- public void finished(boolean success) {
- ioContext.stop();
- notifyFinished(context, success);
- }
- };
- List<String> args = argsToStringList(launchArguments.get("args"));
- List<String> vmArgs = argsToStringList(launchArguments.get("vmArgs"));
- ExplicitProcessParameters params = ExplicitProcessParameters.empty();
- if (!(args.isEmpty() && vmArgs.isEmpty())) {
- ExplicitProcessParameters.Builder bld = ExplicitProcessParameters.builder();
- bld.launcherArgs(vmArgs);
- bld.args(args);
- bld.replaceArgs(false);
- params = bld.build();
- }
- OperationContext ctx = OperationContext.find(Lookup.getDefault());
- ctx.addProgressOperationListener(null, new ProgressOperationListener() {
- @Override
- public void progressHandleCreated(ProgressOperationEvent e) {
- context.setProcessExecutorHandle(e.getProgressHandle());
+ Lookup lookup;
+ if (singleMethod != null) {
+ lookup = Lookups.fixed(toRun, singleMethod, params, ioContext, progress);
+ } else {
+ lookup = Lookups.fixed(toRun, ioContext, params, progress);
}
+ Lookups.executeWith(launchCtx, () -> {
+ providerAndCommand.first().invokeAction(providerAndCommand.second(), lookup);
+
+ });
+ }).exceptionally((t) -> {
+ launchFuture.completeExceptionally(t);
+ return null;
});
- TestProgressHandler testProgressHandler = ctx.getClient().getNbCodeCapabilities().hasTestResultsSupport() ? new TestProgressHandler(ctx.getClient(), context.getClient(), Utils.toUri(toRun)) : null;
+ } else {
+ ExecutionDescriptor executionDescriptor = new ExecutionDescriptor()
+ .showProgress(true)
+ .showSuspended(true)
+ .frontWindowOnError(true)
+ .controllable(true);
Lookup launchCtx = new ProxyLookup(
- testProgressHandler != null ? Lookups.fixed(toRun, ioContext, progress, testProgressHandler) : Lookups.fixed(toRun, ioContext, progress),
+ Lookups.fixed(ioContext, progress),
Lookup.getDefault()
);
+ List<String> args = argsToStringList(launchArguments.get("args"));
+ Lookups.executeWith(launchCtx, () -> {
+ if (debug) {
+ String miDebugger = (String) launchArguments.get("miDebugger");
+ startNativeDebug(nativeImageFile, args, miDebugger, context, executionDescriptor, launchFuture);
+ } else {
+ execNative(nativeImageFile, args, context, executionDescriptor, launchFuture);//, success);
+ }
+ });
+ }
+ return launchFuture;
+ }
- Lookup lookup;
- if (singleMethod != null) {
- lookup = Lookups.fixed(toRun, singleMethod, params, ioContext, progress);
- } else {
- lookup = Lookups.fixed(toRun, ioContext, params, progress);
+ private static void execNative(File nativeImageFile, List<String> args, DebugAdapterContext context, ExecutionDescriptor executionDescriptor, CompletableFuture<Void> launchFuture) {
+ ExecutionService.newService(() -> {
+ launchFuture.complete(null);
+ List<String> command = args.isEmpty() ? Collections.singletonList(nativeImageFile.getAbsolutePath()) : join(nativeImageFile.getAbsolutePath(), args);
+ try {
+ return new ProcessBuilder(command).start();
+ } catch (IOException ex) {
+ ErrorUtilities.completeExceptionally(launchFuture,
+ "Failed to run debuggee native image: " + ex.getLocalizedMessage(),
+ ResponseErrorCode.serverErrorStart);
+ throw ex;
}
- Lookups.executeWith(launchCtx, () -> {
- providerAndCommand.first().invokeAction(providerAndCommand.second(), lookup);
+ }, executionDescriptor, "Run - " + nativeImageFile.getName()).run();
+ }
+
+ private static List<String> join(String first, List<String> next) {
+ List<String> joined = new ArrayList<>(next.size() + 1);
+ joined.add(first);
+ joined.addAll(next);
+ return joined;
+ }
+ private static void startNativeDebug(File nativeImageFile, List<String> args, String miDebugger, DebugAdapterContext context, ExecutionDescriptor executionDescriptor, CompletableFuture<Void> launchFuture) {
+ AtomicReference<NIDebugger> niDebuggerRef = new AtomicReference<>();
+ AtomicReference<NbDebugSession> debugSessionRef = new AtomicReference<>();
+ NIDebugger niDebugger;
+ try {
+ niDebugger = NIDebugRunner.start(nativeImageFile, args, miDebugger, null, null, executionDescriptor, engine -> {
+ Session session = engine.lookupFirst(null, Session.class);
+ NbDebugSession debugSession = new NbDebugSession(session);
+ debugSessionRef.set(debugSession);
+ NIDebugger niDebugger_ = niDebuggerRef.get();
+ if (niDebugger_ != null) {
+ debugSession.setNIDebugger(niDebugger_);
+ }
+ context.setDebugSession(debugSession);
+ launchFuture.complete(null);
+ context.getConfigurationSemaphore().waitForConfigurationDone();
});
- }).exceptionally((t) -> {
- launchFuture.completeExceptionally(t);
- return null;
- });
- return launchFuture;
+ } catch (IllegalStateException ex) {
+ ErrorUtilities.completeExceptionally(launchFuture,
+ "Failed to launch debuggee native image. " + ex.getLocalizedMessage(),
+ ResponseErrorCode.serverErrorStart);
+ return ;
+ }
+ niDebuggerRef.set(niDebugger);
+ NbDebugSession debugSession = debugSessionRef.get();
+ if (debugSession != null) {
+ debugSession.setNIDebugger(niDebugger);
+ }
}
-
+
@NonNull
private List<String> argsToStringList(Object o) {
if (o == null) {
@@ -186,7 +267,7 @@ public abstract class NbLaunchDelegate {
}
}
- private CompletableFuture<Pair<ActionProvider, String>> findTargetWithPossibleRebuild(FileObject toRun, SingleMethod singleMethod, boolean debug, boolean testRun, NbProcessConsole ioContext) throws IllegalArgumentException {
+ private static CompletableFuture<Pair<ActionProvider, String>> findTargetWithPossibleRebuild(FileObject toRun, SingleMethod singleMethod, boolean debug, boolean testRun, NbProcessConsole ioContext) throws IllegalArgumentException {
Pair<ActionProvider, String> providerAndCommand = findTarget(toRun, singleMethod, debug, testRun);
if (providerAndCommand != null) {
return CompletableFuture.completedFuture(providerAndCommand);
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/launch/NbLaunchRequestHandler.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/launch/NbLaunchRequestHandler.java
index 51072b5..b20629b 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/launch/NbLaunchRequestHandler.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/launch/NbLaunchRequestHandler.java
@@ -53,6 +53,7 @@ public final class NbLaunchRequestHandler {
private NbLaunchDelegate activeLaunchHandler;
public CompletableFuture<Void> launch(Map<String, Object> launchArguments, DebugAdapterContext context) {
+ boolean isNative = "nativeimage".equals(launchArguments.get("type"));
CompletableFuture<Void> resultFuture = new CompletableFuture<>();
boolean noDebug = (Boolean) launchArguments.getOrDefault("noDebug", Boolean.FALSE);
Consumer<DebugAdapterContext> terminateHandle = (daContext) -> handleTerminatedEvent(daContext);
@@ -61,8 +62,8 @@ public final class NbLaunchRequestHandler {
// validation
List<String> modulePaths = (List<String>) launchArguments.getOrDefault("modulePaths", Collections.emptyList());
List<String> classPaths = (List<String>) launchArguments.getOrDefault("classPaths", Collections.emptyList());
- if (StringUtils.isBlank((String)launchArguments.get("mainClass"))
- || modulePaths.isEmpty() && classPaths.isEmpty()) {
+ if (!isNative && (StringUtils.isBlank((String)launchArguments.get("mainClass"))
+ || modulePaths.isEmpty() && classPaths.isEmpty())) {
ErrorUtilities.completeExceptionally(resultFuture,
"Failed to launch debuggee VM. Missing mainClass or modulePaths/classPaths options in launch configuration.",
ResponseErrorCode.serverErrorStart);
@@ -80,37 +81,52 @@ public final class NbLaunchRequestHandler {
context.setDebuggeeEncoding(Charset.forName((String)launchArguments.get("encoding")));
}
- if (StringUtils.isBlank((String)launchArguments.get("vmArgs"))) {
- launchArguments.put("vmArgs", String.format("-Dfile.encoding=%s", context.getDebuggeeEncoding().name()));
- } else {
- // if vmArgs already has the file.encoding settings, duplicate options for jvm will not cause an error, the right most value wins
- launchArguments.put("vmArgs", String.format("%s -Dfile.encoding=%s", launchArguments.get("vmArgs"), context.getDebuggeeEncoding().name()));
+ if (!isNative) {
+ if (StringUtils.isBlank((String)launchArguments.get("vmArgs"))) {
+ launchArguments.put("vmArgs", String.format("-Dfile.encoding=%s", context.getDebuggeeEncoding().name()));
+ } else {
+ // if vmArgs already has the file.encoding settings, duplicate options for jvm will not cause an error, the right most value wins
+ launchArguments.put("vmArgs", String.format("%s -Dfile.encoding=%s", launchArguments.get("vmArgs"), context.getDebuggeeEncoding().name()));
+ }
}
context.setDebugMode(!noDebug);
activeLaunchHandler.preLaunch(launchArguments, context);
String filePath = (String)launchArguments.get("mainClass");
- File ioFile = null;
- if (filePath != null) {
- ioFile = new File(filePath);
- if (!ioFile.exists()) {
- try {
- URI uri = new URI(filePath);
- ioFile = Utilities.toFile(uri);
- } catch (URISyntaxException ex) {
- // Not a valid file
+ FileObject file = null;
+ File nativeImageFile = null;
+ if (!isNative) {
+ File ioFile = null;
+ if (filePath != null) {
+ ioFile = new File(filePath);
+ if (!ioFile.exists()) {
+ try {
+ URI uri = new URI(filePath);
+ ioFile = Utilities.toFile(uri);
+ } catch (URISyntaxException ex) {
+ // Not a valid file
+ }
}
}
- }
- FileObject file = ioFile != null ? FileUtil.toFileObject(ioFile) : null;
- if (file == null) {
- ErrorUtilities.completeExceptionally(resultFuture,
- "Missing file: " + filePath,
+ file = ioFile != null ? FileUtil.toFileObject(ioFile) : null;
+ if (file == null) {
+ ErrorUtilities.completeExceptionally(resultFuture,
+ "Missing file: " + filePath,
+ ResponseErrorCode.serverErrorStart);
+ return resultFuture;
+ }
+ } else {
+ String nativeImage = (String) launchArguments.get("nativeImagePath");
+ if (nativeImage == null) {
+ ErrorUtilities.completeExceptionally(resultFuture,
+ "Failed to launch debuggee native image. No native image is specified.",
ResponseErrorCode.serverErrorStart);
- return resultFuture;
+ return resultFuture;
+ }
+ nativeImageFile = new File(nativeImage);
}
- if (!launchArguments.containsKey("sourcePaths")) {
+ if (!isNative && !launchArguments.containsKey("sourcePaths")) {
ClassPath sourceCP = ClassPath.getClassPath(file, ClassPath.SOURCE);
if (sourceCP != null) {
FileObject[] roots = sourceCP.getRoots();
@@ -125,7 +141,7 @@ public final class NbLaunchRequestHandler {
}
String singleMethod = (String)launchArguments.get("methodName");
boolean testRun = (Boolean) launchArguments.getOrDefault("testRun", Boolean.FALSE);
- activeLaunchHandler.nbLaunch(file, singleMethod, launchArguments, context, !noDebug, testRun, new OutputListener(context)).thenRun(() -> {
+ activeLaunchHandler.nbLaunch(file, nativeImageFile, singleMethod, launchArguments, context, !noDebug, testRun, new OutputListener(context)).thenRun(() -> {
activeLaunchHandler.postLaunch(launchArguments, context);
resultFuture.complete(null);
}).exceptionally(e -> {
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/variables/NbVariablesRequestHandler.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/variables/NbVariablesRequestHandler.java
index bd76604..b1627d2 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/variables/NbVariablesRequestHandler.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/variables/NbVariablesRequestHandler.java
@@ -28,8 +28,8 @@ import org.eclipse.lsp4j.debug.Variable;
import org.eclipse.lsp4j.debug.VariablesArguments;
import org.eclipse.lsp4j.debug.VariablesResponse;
import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode;
+import org.netbeans.api.debugger.Session;
-import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.modules.java.lsp.server.debugging.DebugAdapterContext;
import org.netbeans.modules.java.lsp.server.debugging.NbScope;
import org.netbeans.modules.java.lsp.server.debugging.launch.NbDebugSession;
@@ -63,8 +63,8 @@ public final class NbVariablesRequestHandler {
// Nothing, or an old container
response.setVariables(new Variable[0]);
} else {
- JPDADebugger debugger = context.getDebugSession().getDebugger();
- Models.CompoundModel localsModel = localsModelProvider.getModel(debugger.getSession());
+ Session session = context.getDebugSession().getSession();
+ Models.CompoundModel localsModel = localsModelProvider.getModel(session);
int threadId;
if (container instanceof NbScope) {
threadId = ((NbScope) container).getFrame().getThreadId();
@@ -84,14 +84,21 @@ public final class NbVariablesRequestHandler {
}
for (Object child : children) {
String name = localsModel.getDisplayName(child);
- String value = String.valueOf(localsModel.getValueAt(child, LOCALS_TO_STRING_COLUMN_ID));
+ String value;
+ try {
+ value = String.valueOf(localsModel.getValueAt(child, LOCALS_TO_STRING_COLUMN_ID));
+ } catch (UnknownTypeException ex) {
+ value = String.valueOf(localsModel.getValueAt(child, LOCALS_VALUE_COLUMN_ID));
+ }
String type = String.valueOf(localsModel.getValueAt(child, LOCALS_TYPE_COLUMN_ID));
- int id = context.getThreadsProvider().getThreadObjects().addObject(threadId, child);
Variable variable = new Variable();
variable.setName(name);
variable.setValue(value);
variable.setType(type);
- variable.setVariablesReference(id);
+ if (!localsModel.isLeaf(child)) {
+ int id = context.getThreadsProvider().getThreadObjects().addObject(threadId, child);
+ variable.setVariablesReference(id);
+ }
list.add(variable);
}
} catch (UnknownTypeException e) {
@@ -132,8 +139,8 @@ public final class NbVariablesRequestHandler {
return future;
}
- JPDADebugger debugger = ((NbDebugSession) context.getDebugSession()).getDebugger();
- Models.CompoundModel localsModel = localsModelProvider.getModel(debugger.getSession());
+ Session session = ((NbDebugSession) context.getDebugSession()).getSession();
+ Models.CompoundModel localsModel = localsModelProvider.getModel(session);
int threadId;
if (container instanceof NbScope) {
diff --git a/java/java.lsp.server/vscode/package.json b/java/java.lsp.server/vscode/package.json
index 45b3736..f63cec2 100644
--- a/java/java.lsp.server/vscode/package.json
+++ b/java/java.lsp.server/vscode/package.json
@@ -148,6 +148,61 @@
}
}
]
+ },
+ {
+ "type": "nativeimage",
+ "label": "Native Image",
+ "runtime": "node",
+ "languages": [
+ "java"
+ ],
+ "configurationAttributes": {
+ "launch": {
+ "required": [
+ "nativeImagePath"
+ ],
+ "properties": {
+ "nativeImagePath": {
+ "type": "string",
+ "description": "Absolute path to the application native image.",
+ "default": "${workspaceFolder}/build/native-image/application"
+ },
+ "miDebugger": {
+ "type": "string",
+ "description": "MI Debugger",
+ "default": "gdb"
+ },
+ "console": {
+ "type": "string",
+ "enum": [
+ "internalConsole"
+ ],
+ "description": "The specified console to launch the program.",
+ "default": "internalConsole"
+ }
+ }
+ }
+ },
+ "initialConfigurations": [
+ {
+ "type": "nativeimage",
+ "request": "launch",
+ "name": "Launch Native Image",
+ "nativeImagePath": "${workspaceFolder}/build/native-image/application"
+ }
+ ],
+ "configurationSnippets": [
+ {
+ "label": "Launch Native Image",
+ "description": "Launch a native image with MI debugger.",
+ "body": {
+ "type": "nativeimage",
+ "request": "launch",
+ "name": "Launch Native Image",
+ "nativeImagePath": "^\"${1:\\${workspaceFolder\\}/build/native-image/application}\""
+ }
+ }
+ ]
}
],
"commands": [
diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts
index bc83afe..e0a6bfb 100644
--- a/java/java.lsp.server/vscode/src/extension.ts
+++ b/java/java.lsp.server/vscode/src/extension.ts
@@ -174,9 +174,12 @@ export function activate(context: ExtensionContext): VSNetBeansAPI {
//register debugger:
let configProvider = new NetBeansConfigurationProvider();
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('java8+', configProvider));
+ let configNativeProvider = new NetBeansConfigurationNativeProvider();
+ context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('nativeimage', configNativeProvider));
let debugDescriptionFactory = new NetBeansDebugAdapterDescriptionFactory();
context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory('java8+', debugDescriptionFactory));
+ context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory('nativeimage', debugDescriptionFactory));
// register commands
context.subscriptions.push(commands.registerCommand('java.workspace.compile', () => {
@@ -655,3 +658,26 @@ class NetBeansConfigurationProvider implements vscode.DebugConfigurationProvider
return config;
}
}
+
+class NetBeansConfigurationNativeProvider implements vscode.DebugConfigurationProvider {
+
+ resolveDebugConfiguration(_folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration, _token?: vscode.CancellationToken): vscode.ProviderResult<vscode.DebugConfiguration> {
+ if (!config.type) {
+ config.type = 'nativeimage';
+ }
+ if (!config.request) {
+ config.request = 'launch';
+ }
+ if (!config.nativeImagePath) {
+ config.nativeImagePath = '${workspaceFolder}/build/native-image/application';
+ }
+ if (!config.miDebugger) {
+ config.miDebugger = 'gdb';
+ }
+ if (!config.console) {
+ config.console = 'internalConsole';
+ }
+
+ return config;
+ }
+}
diff --git a/java/java.nativeimage.debugger/build.xml b/java/java.nativeimage.debugger/build.xml
new file mode 100644
index 0000000..6f55714
--- /dev/null
+++ b/java/java.nativeimage.debugger/build.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<!-- You may freely edit this file. See harness/README in the NetBeans platform -->
+<!-- for some information on what you could do (e.g. targets to override). -->
+<!-- If you delete this file and reopen the project it will be recreated. -->
+<project name="java/java.nativeimage.debugger" default="netbeans" basedir=".">
+ <description>Builds, tests, and runs the project org.netbeans.modules.java.nativeimage.debugger.</description>
+ <import file="../../nbbuild/templates/projectized.xml"/>
+</project>
diff --git a/java/java.nativeimage.debugger/manifest.mf b/java/java.nativeimage.debugger/manifest.mf
new file mode 100644
index 0000000..7fd02de
--- /dev/null
+++ b/java/java.nativeimage.debugger/manifest.mf
@@ -0,0 +1,7 @@
+Manifest-Version: 1.0
+AutoUpdate-Show-In-Client: false
+OpenIDE-Module: org.netbeans.modules.java.nativeimage.debugger/0
+OpenIDE-Module-Layer: org/netbeans/modules/java/nativeimage/debugger/resources/mf-layer.xml
+OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/java/nativeimage/debugger/Bundle.properties
+OpenIDE-Module-Specification-Version: 0.1
+
diff --git a/java/java.nativeimage.debugger/nbproject/project.properties b/java/java.nativeimage.debugger/nbproject/project.properties
new file mode 100644
index 0000000..5137752
--- /dev/null
+++ b/java/java.nativeimage.debugger/nbproject/project.properties
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+javac.source=1.8
+javac.compilerargs=-Xlint -Xlint:-serial
diff --git a/cpplite/cpplite.debugger/nbproject/project.xml b/java/java.nativeimage.debugger/nbproject/project.xml
similarity index 78%
copy from cpplite/cpplite.debugger/nbproject/project.xml
copy to java/java.nativeimage.debugger/nbproject/project.xml
index d360c06..21f442c 100644
--- a/cpplite/cpplite.debugger/nbproject/project.xml
+++ b/java/java.nativeimage.debugger/nbproject/project.xml
@@ -23,7 +23,7 @@
<type>org.netbeans.modules.apisupport.project</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
- <code-name-base>org.netbeans.modules.cpplite.debugger</code-name-base>
+ <code-name-base>org.netbeans.modules.java.nativeimage.debugger</code-name-base>
<module-dependencies>
<dependency>
<code-name-base>org.netbeans.api.annotations.common</code-name-base>
@@ -44,74 +44,96 @@
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.netbeans.modules.dlight.nativeexecution</code-name-base>
+ <code-name-base>org.netbeans.api.debugger.jpda</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>1.48</specification-version>
+ <release-version>2</release-version>
+ <specification-version>3.20</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.netbeans.modules.projectapi</code-name-base>
+ <code-name-base>org.netbeans.api.java.classpath</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
<release-version>1</release-version>
- <specification-version>1.75</specification-version>
+ <specification-version>1.65</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.netbeans.spi.debugger.ui</code-name-base>
+ <code-name-base>org.netbeans.modules.extexecution</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>2</release-version>
+ <specification-version>1.59</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.netbeans.modules.java.project</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
<release-version>1</release-version>
- <specification-version>2.62</specification-version>
+ <specification-version>1.83</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.netbeans.spi.viewmodel</code-name-base>
+ <code-name-base>org.netbeans.modules.nativeimage.api</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <release-version>2</release-version>
- <specification-version>1.59</specification-version>
+ <release-version>0</release-version>
+ <specification-version>0.1</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.awt</code-name-base>
+ <code-name-base>org.netbeans.modules.projectapi</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>7.76</specification-version>
+ <release-version>1</release-version>
+ <specification-version>1.75</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.filesystems</code-name-base>
+ <code-name-base>org.netbeans.modules.projectuiapi</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>9.18</specification-version>
+ <release-version>1</release-version>
+ <specification-version>1.99</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.loaders</code-name-base>
+ <code-name-base>org.netbeans.spi.debugger.ui</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>7.76</specification-version>
+ <release-version>1</release-version>
+ <specification-version>2.62</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.modules</code-name-base>
+ <code-name-base>org.netbeans.spi.viewmodel</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>7.56</specification-version>
+ <release-version>2</release-version>
+ <specification-version>1.59</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
+ <code-name-base>org.openide.awt</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <specification-version>7.76</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.nodes</code-name-base>
+ <code-name-base>org.openide.dialogs</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
@@ -119,43 +141,43 @@
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.text</code-name-base>
+ <code-name-base>org.openide.filesystems</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>6.75</specification-version>
+ <specification-version>9.18</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.util</code-name-base>
+ <code-name-base>org.openide.modules</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>9.15</specification-version>
+ <specification-version>7.60</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.util.lookup</code-name-base>
+ <code-name-base>org.openide.util</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>8.41</specification-version>
+ <specification-version>9.15</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.util.ui</code-name-base>
+ <code-name-base>org.openide.util.lookup</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>9.16</specification-version>
+ <specification-version>8.41</specification-version>
</run-dependency>
</dependency>
<dependency>
- <code-name-base>org.openide.windows</code-name-base>
+ <code-name-base>org.openide.util.ui</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>6.85</specification-version>
+ <specification-version>9.20</specification-version>
</run-dependency>
</dependency>
</module-dependencies>
@@ -186,13 +208,9 @@
</test-type>
</test-dependencies>
<friend-packages>
- <friend>org.netbeans.modules.cpplite.project</friend>
- <package>org.netbeans.modules.cpplite.debugger.api</package>
+ <friend>org.netbeans.modules.java.lsp.server</friend>
+ <package>org.netbeans.modules.java.nativeimage.debugger.api</package>
</friend-packages>
- <class-path-extension>
- <runtime-relative-path>ext/cpplite-mi-f8f8250283be.jar</runtime-relative-path>
- <binary-origin>external/cpplite-mi-f8f8250283be.jar</binary-origin>
- </class-path-extension>
</data>
</configuration>
</project>
diff --git a/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/Bundle.properties b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/Bundle.properties
new file mode 100644
index 0000000..9afa08a
--- /dev/null
+++ b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/Bundle.properties
@@ -0,0 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# manifest's description entries
+OpenIDE-Module-Display-Category=Debugging
+OpenIDE-Module-Name=JVM Native Image Debugger
diff --git a/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/actions/Bundle.properties b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/actions/Bundle.properties
new file mode 100644
index 0000000..d033bba
--- /dev/null
+++ b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/actions/Bundle.properties
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+NIAttachCustomizer.fileLabel.text=Image File:
+NIAttachCustomizer.fileTextField.text=
+NIAttachCustomizer.fileButton.text=Browse
+NIAttachCustomizer.dbgLabel.text=Debugger:
diff --git a/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/actions/NIAttachCustomizer.form b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/actions/NIAttachCustomizer.form
new file mode 100644
index 0000000..541b070
--- /dev/null
+++ b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/actions/NIAttachCustomizer.form
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+ <AuxValues>
+ <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+ <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+ <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+ <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+ <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+ <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+ <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+ <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+ <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+ </AuxValues>
+
+ <Layout>
+ <DimensionLayout dim="0">
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Group type="102" attributes="0">
+ <EmptySpace max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Group type="102" alignment="0" attributes="0">
+ <Component id="fileLabel" min="-2" max="-2" attributes="0"/>
+ <EmptySpace max="-2" attributes="0"/>
+ <Component id="fileTextField" max="32767" attributes="0"/>
+ </Group>
+ <Group type="102" alignment="0" attributes="0">
+ <Component id="dbgLabel" min="-2" max="-2" attributes="0"/>
+ <EmptySpace max="-2" attributes="0"/>
+ <Component id="dbgComboBox" pref="196" max="32767" attributes="0"/>
+ </Group>
+ </Group>
+ <EmptySpace max="-2" attributes="0"/>
+ <Component id="fileButton" min="-2" max="-2" attributes="0"/>
+ <EmptySpace max="-2" attributes="0"/>
+ </Group>
+ </Group>
+ </DimensionLayout>
+ <DimensionLayout dim="1">
+ <Group type="103" groupAlignment="0" attributes="0">
+ <Group type="102" alignment="0" attributes="0">
+ <EmptySpace max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="3" attributes="0">
+ <Component id="fileLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+ <Component id="fileTextField" alignment="3" min="-2" max="-2" attributes="0"/>
+ <Component id="fileButton" alignment="3" min="-2" max="-2" attributes="0"/>
+ </Group>
+ <EmptySpace max="-2" attributes="0"/>
+ <Group type="103" groupAlignment="3" attributes="0">
+ <Component id="dbgLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+ <Component id="dbgComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
+ </Group>
+ <EmptySpace max="32767" attributes="0"/>
+ </Group>
+ </Group>
+ </DimensionLayout>
+ </Layout>
+ <SubComponents>
+ <Component class="javax.swing.JLabel" name="fileLabel">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/java/nativeimage/debugger/actions/Bundle.properties" key="NIAttachCustomizer.fileLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ </Component>
+ <Component class="javax.swing.JTextField" name="fileTextField">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/java/nativeimage/debugger/actions/Bundle.properties" key="NIAttachCustomizer.fileTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ </Component>
+ <Component class="javax.swing.JButton" name="fileButton">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/java/nativeimage/debugger/actions/Bundle.properties" key="NIAttachCustomizer.fileButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ <Events>
+ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="fileButtonActionPerformed"/>
+ </Events>
+ </Component>
+ <Component class="javax.swing.JLabel" name="dbgLabel">
+ <Properties>
+ <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+ <ResourceString bundle="org/netbeans/modules/java/nativeimage/debugger/actions/Bundle.properties" key="NIAttachCustomizer.dbgLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
+ </Property>
+ </Properties>
+ </Component>
+ <Component class="javax.swing.JComboBox" name="dbgComboBox">
+ <Properties>
+ <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+ <StringArray count="2">
+ <StringItem index="0" value="gdb"/>
+ <StringItem index="1" value="lldb-mi"/>
+ </StringArray>
+ </Property>
+ </Properties>
+ <AuxValues>
+ <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
+ </AuxValues>
+ </Component>
+ </SubComponents>
+</Form>
diff --git a/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/actions/NIAttachCustomizer.java b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/actions/NIAttachCustomizer.java
new file mode 100644
index 0000000..0d1fe63
--- /dev/null
+++ b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/actions/NIAttachCustomizer.java
@@ -0,0 +1,378 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.nativeimage.debugger.actions;
+
+import java.awt.event.ActionEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collections;
+import javax.swing.Action;
+import javax.swing.JFileChooser;
+import javax.swing.SwingUtilities;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.filechooser.FileFilter;
+
+import org.netbeans.api.debugger.Properties;
+import org.netbeans.api.project.FileOwnerQuery;
+import org.netbeans.api.project.Project;
+import org.netbeans.modules.java.nativeimage.debugger.api.NIDebugRunner;
+import org.netbeans.spi.debugger.ui.Controller;
+import static org.netbeans.spi.debugger.ui.Controller.PROP_VALID;
+import org.netbeans.spi.debugger.ui.PersistentController;
+import static org.netbeans.spi.project.ActionProvider.COMMAND_DEBUG;
+import org.openide.DialogDisplayer;
+import org.openide.NotifyDescriptor;
+import org.openide.awt.Actions;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.modules.ModuleInfo;
+import org.openide.modules.Modules;
+import org.openide.util.Exceptions;
+import org.openide.util.NbBundle;
+import org.openide.util.RequestProcessor;
+import org.openide.util.Utilities;
+
+/**
+ *
+ * @author martin
+ */
+public class NIAttachCustomizer extends javax.swing.JPanel {
+
+ private final ConnectController controller;
+ private final ValidityDocumentListener validityDocumentListener = new ValidityDocumentListener();
+ private final RequestProcessor currentFileRP = new RequestProcessor(NIAttachCustomizer.class);
+
+ /**
+ * Creates new form NIAttachCustomizer
+ */
+ public NIAttachCustomizer() {
+ controller = new ConnectController();
+ initComponents();
+ fileTextField.getDocument().addDocumentListener(validityDocumentListener);
+ initNIFile();
+ }
+
+ private void initNIFile() {
+ currentFileRP.post(() -> {
+ FileObject currentFO = Utilities.actionsGlobalContext().lookup(FileObject.class);
+ if (currentFO != null) {
+ File currentFile = FileUtil.toFile(currentFO);
+ String path;
+ if (currentFile != null && currentFile.canExecute()) {
+ path = currentFile.getAbsolutePath();
+ } else {
+ Project project = FileOwnerQuery.getOwner(currentFO);
+ if (project != null) {
+ currentFO = project.getProjectDirectory();
+ currentFile = FileUtil.toFile(currentFO);
+ path = currentFile.getAbsolutePath();
+ } else {
+ path = null;
+ }
+ }
+ if (path != null) {
+ SwingUtilities.invokeLater(() -> {
+ fileTextField.setText(path);
+ });
+ }
+ }
+ });
+ }
+
+ /**
+ * This method is called from within the constructor to initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is always
+ * regenerated by the Form Editor.
+ */
+ @SuppressWarnings("unchecked")
+ // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+ private void initComponents() {
+
+ fileLabel = new javax.swing.JLabel();
+ fileTextField = new javax.swing.JTextField();
+ fileButton = new javax.swing.JButton();
+ dbgLabel = new javax.swing.JLabel();
+ dbgComboBox = new javax.swing.JComboBox<>();
+
+ org.openide.awt.Mnemonics.setLocalizedText(fileLabel, org.openide.util.NbBundle.getMessage(NIAttachCustomizer.class, "NIAttachCustomizer.fileLabel.text")); // NOI18N
+
+ fileTextField.setText(org.openide.util.NbBundle.getMessage(NIAttachCustomizer.class, "NIAttachCustomizer.fileTextField.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(fileButton, org.openide.util.NbBundle.getMessage(NIAttachCustomizer.class, "NIAttachCustomizer.fileButton.text")); // NOI18N
+ fileButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ fileButtonActionPerformed(evt);
+ }
+ });
+
+ org.openide.awt.Mnemonics.setLocalizedText(dbgLabel, org.openide.util.NbBundle.getMessage(NIAttachCustomizer.class, "NIAttachCustomizer.dbgLabel.text")); // NOI18N
+
+ dbgComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "gdb", "lldb-mi" }));
+
+ javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+ this.setLayout(layout);
+ layout.setHorizontalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(fileLabel)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(fileTextField))
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(dbgLabel)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(dbgComboBox, 0, 196, Short.MAX_VALUE)))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(fileButton)
+ .addContainerGap())
+ );
+ layout.setVerticalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(fileLabel)
+ .addComponent(fileTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(fileButton))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(dbgLabel)
+ .addComponent(dbgComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ );
+ }// </editor-fold>//GEN-END:initComponents
+
+ @NbBundle.Messages({"CTL_ExecutableFiles=Executable Files"})
+ private void fileButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileButtonActionPerformed
+ JFileChooser chooser = new JFileChooser(fileTextField.getText());
+ chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+ chooser.setFileFilter(new FileFilter() {
+ @Override
+ public boolean accept(File f) {
+ return f.isDirectory() || f.canExecute();
+ }
+
+ @Override
+ public String getDescription() {
+ return Bundle.CTL_ExecutableFiles();
+ }
+ });
+ if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
+ fileTextField.setText(chooser.getSelectedFile().getAbsolutePath());
+ }
+ }//GEN-LAST:event_fileButtonActionPerformed
+
+
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JComboBox<String> dbgComboBox;
+ private javax.swing.JLabel dbgLabel;
+ private javax.swing.JButton fileButton;
+ private javax.swing.JLabel fileLabel;
+ private javax.swing.JTextField fileTextField;
+ // End of variables declaration//GEN-END:variables
+
+ RequestProcessor.Task validationTask = currentFileRP.create(new FileValidationTask());
+
+ @NbBundle.Messages({"MSG_NoFile=Native Imige File is missing."})
+ private void checkValid() {
+ assert SwingUtilities.isEventDispatchThread() : "Called outside of AWT.";
+ if (fileTextField.getText().isEmpty()) {
+ controller.setInformationMessage(Bundle.MSG_NoFile());
+ controller.setValid(false);
+ return ;
+ }
+ validationTask.schedule(200);
+ }
+
+ private class FileValidationTask implements Runnable {
+
+ @Override
+ public void run() {
+ String filePath = fileTextField.getText();
+ File file = new File(filePath);
+ boolean canExecute = file.isFile() && file.canExecute();
+ SwingUtilities.invokeLater(() -> {
+ controller.setValid(canExecute);
+ String message = canExecute ? null : Bundle.MSG_NoFile();
+ controller.setInformationMessage(message);
+ });
+ }
+ }
+
+ private class ValidityDocumentListener implements DocumentListener {
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ checkValid();
+ }
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ checkValid();
+ }
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+ checkValid();
+ }
+ }
+
+ Controller getController() {
+ return controller;
+ }
+
+ private static final String CPPLITE_DEBUGGER = "org.netbeans.modules.cpplite.debugger"; // NOI18N
+
+ @NbBundle.Messages({"MSG_EnableNativeDebugger=Enable {0} in Plugins Manager", "TTL_EnableNativeDebugger=Native Debugger Dependency"})
+ private static boolean checkCPPLite() {
+ ModuleInfo cppliteDebugger = Modules.getDefault().findCodeNameBase(CPPLITE_DEBUGGER);
+ if (cppliteDebugger != null && !cppliteDebugger.isEnabled()) {
+ Action pluginsManager = Actions.forID("System", "org.netbeans.modules.autoupdate.ui.actions.PluginManagerAction");
+ String moduleDisplayName = cppliteDebugger.getDisplayName();
+ NotifyDescriptor messageDescriptor = new NotifyDescriptor.Confirmation(
+ Bundle.MSG_EnableNativeDebugger(moduleDisplayName),
+ Bundle.TTL_EnableNativeDebugger(),
+ NotifyDescriptor.OK_CANCEL_OPTION);
+ if (NotifyDescriptor.OK_OPTION.equals(DialogDisplayer.getDefault().notify(messageDescriptor))) {
+ SwingUtilities.invokeLater(() -> {
+ ActionEvent ev = new ActionEvent(pluginsManager, 100, "installed");
+ pluginsManager.actionPerformed(ev);
+ });
+ }
+ return false;
+ }
+ return true;
+ }
+
+ public class ConnectController implements PersistentController {
+
+ private static final String NI_ATTACH_PROPERTIES = "native_image_attach_settings";
+ private static final String PROP_NI_FILE = "niFile";
+ private static final String PROP_DBG = "debugger";
+
+ private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+ private boolean valid = true;
+
+ @Override
+ public String getDisplayName() {
+ return dbgComboBox.getSelectedItem() + " " + new File(fileTextField.getText()).getName();
+ }
+
+ @Override
+ public boolean load(Properties props) {
+ assert !SwingUtilities.isEventDispatchThread();
+ final Properties attachProps = props.getProperties(NI_ATTACH_PROPERTIES);
+ try {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ fileTextField.setText(attachProps.getString(PROP_NI_FILE, ""));
+ dbgComboBox.setSelectedItem(attachProps.getString(PROP_DBG, "DBG"));
+ }
+ });
+ } catch (InterruptedException | InvocationTargetException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ return true;
+ }
+
+ @Override
+ public void save(Properties props) {
+ final Properties attachProps = props.getProperties(NI_ATTACH_PROPERTIES);
+ if (SwingUtilities.isEventDispatchThread()) {
+ saveToProps(attachProps);
+ } else {
+ try {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ saveToProps(attachProps);
+
+ }
+ });
+ } catch (InterruptedException ex) {
+ Exceptions.printStackTrace(ex);
+ } catch (InvocationTargetException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ }
+
+ private void saveToProps(Properties attachProps) {
+ attachProps.setString(PROP_NI_FILE, fileTextField.getText());
+ attachProps.setString(PROP_DBG, (String) dbgComboBox.getSelectedItem());
+ }
+
+ @Override
+ public boolean ok() {
+ String filePath = fileTextField.getText();
+ String debuggerCommand = dbgComboBox.getSelectedItem().toString();
+ currentFileRP.post(() -> {
+ if (!checkCPPLite()) {
+ return ;
+ }
+ File file = new File(filePath);
+ String displayName = COMMAND_DEBUG + " " + file.getName();
+ NIDebugRunner.start(file, Collections.emptyList(), debuggerCommand, null, displayName, null, null);
+ });
+ return true;
+ }
+
+ @Override
+ public boolean cancel() {
+ return true;
+ }
+
+ @Override
+ public boolean isValid() {
+ return valid;
+ }
+
+ void setValid(boolean valid) {
+ this.valid = valid;
+ firePropertyChange(PROP_VALID, !valid, valid);
+ }
+
+ void setErrorMessage(String msg) {
+ firePropertyChange(NotifyDescriptor.PROP_ERROR_NOTIFICATION, null, msg);
+ }
+
+ void setInformationMessage(String msg) {
+ firePropertyChange(NotifyDescriptor.PROP_INFO_NOTIFICATION, null, msg);
+ }
+
+ private void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
+ pcs.firePropertyChange(propertyName, oldValue, newValue);
+ }
+
+ @Override
+ public void addPropertyChangeListener(PropertyChangeListener l) {
+ pcs.addPropertyChangeListener(l);
+ }
+
+ @Override
+ public void removePropertyChangeListener(PropertyChangeListener l) {
+ pcs.removePropertyChangeListener(l);
+ }
+
+ }
+
+}
diff --git a/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/actions/NIAttachType.java b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/actions/NIAttachType.java
new file mode 100644
index 0000000..ba21ff0
--- /dev/null
+++ b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/actions/NIAttachType.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.nativeimage.debugger.actions;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import javax.swing.JComponent;
+
+import org.netbeans.spi.debugger.ui.AttachType;
+import org.netbeans.spi.debugger.ui.Controller;
+import org.openide.util.NbBundle;
+
+/**
+ *
+ * @author martin
+ */
+@NbBundle.Messages("CTL_NIConnector_name=Native Image")
+@AttachType.Registration(displayName="#CTL_NIConnector_name")
+public class NIAttachType extends AttachType {
+
+ private Reference<NIAttachCustomizer> customizerRef = new WeakReference<>(null);
+
+ @Override
+ public JComponent getCustomizer() {
+ NIAttachCustomizer ac = new NIAttachCustomizer();
+ customizerRef = new WeakReference<>(ac);
+ return ac;
+ }
+
+ @Override
+ public Controller getController() {
+ NIAttachCustomizer panel = customizerRef.get();
+ if (panel != null) {
+ return panel.getController();
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/api/NIDebugRunner.java b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/api/NIDebugRunner.java
new file mode 100644
index 0000000..cbb6770
--- /dev/null
+++ b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/api/NIDebugRunner.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.nativeimage.debugger.api;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+
+import org.netbeans.api.debugger.DebuggerEngine;
+import org.netbeans.api.extexecution.ExecutionDescriptor;
+import org.netbeans.api.project.Project;
+import org.netbeans.modules.nativeimage.api.debug.NIDebugger;
+import org.netbeans.modules.java.nativeimage.debugger.breakpoints.JPDABreakpointsHandler;
+import org.netbeans.modules.java.nativeimage.debugger.displayer.JavaFrameDisplayer;
+import org.netbeans.modules.java.nativeimage.debugger.displayer.JavaVariablesDisplayer;
+import static org.netbeans.spi.project.ActionProvider.COMMAND_DEBUG;
+
+/**
+ * Runs debugger with Java translations on a native image.
+ *
+ * @author martin
+ */
+public final class NIDebugRunner {
+
+ private NIDebugRunner() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Starts Native Image debugger.
+ *
+ * @param niFile Native Image file
+ * @param arguments a list of arguments when executing the native image
+ * @param debuggerCommand the debugger command
+ * @param project a project associated with the native image, or <code>null</code>
+ * @param displayName display name of the execution
+ * @param executionDescriptor execution descriptor
+ * @param startedEngine consumer of the started {@link DebuggerEngine}.
+ * @return an instance of {@link NIDebugger}.
+ * @throws IllegalStateException when the native debugger is not available.
+ */
+ public static NIDebugger start(File niFile, List<String> arguments, String debuggerCommand, Project project, String displayName, ExecutionDescriptor executionDescriptor, Consumer<DebuggerEngine> startedEngine) throws IllegalStateException {
+ JavaVariablesDisplayer variablesDisplayer = new JavaVariablesDisplayer();
+ JavaFrameDisplayer frameDisplayer = new JavaFrameDisplayer(project);
+ NIDebugger debugger = NIDebugger.newBuilder()
+ .frameDisplayer(frameDisplayer)
+ .variablesDisplayer(variablesDisplayer)
+ .build();
+ variablesDisplayer.setDebugger(debugger);
+ JPDABreakpointsHandler breakpointsHandler = new JPDABreakpointsHandler(niFile, debugger);
+ File workingDirectory = new File(System.getProperty("user.dir"));
+ List<String> command = arguments.isEmpty() ? Collections.singletonList(niFile.getAbsolutePath()) : join(niFile.getAbsolutePath(), arguments);
+ debugger.start(
+ command,
+ workingDirectory,
+ debuggerCommand,
+ COMMAND_DEBUG + " " + niFile.getName(),
+ executionDescriptor,
+ startedEngine).thenRun(() -> {
+ breakpointsHandler.dispose();
+ });
+ return debugger;
+ }
+
+ private static List<String> join(String first, List<String> next) {
+ List<String> joined = new ArrayList<>(next.size() + 1);
+ joined.add(first);
+ joined.addAll(next);
+ return joined;
+ }
+
+}
diff --git a/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/breakpoints/JPDABreakpointsHandler.java b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/breakpoints/JPDABreakpointsHandler.java
new file mode 100644
index 0000000..2f43091
--- /dev/null
+++ b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/breakpoints/JPDABreakpointsHandler.java
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.nativeimage.debugger.breakpoints;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.Set;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.netbeans.api.debugger.Breakpoint;
+import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.DebuggerManagerAdapter;
+import org.netbeans.api.debugger.jpda.JPDABreakpoint;
+import org.netbeans.api.debugger.jpda.LineBreakpoint;
+import org.netbeans.api.java.classpath.GlobalPathRegistry;
+import org.netbeans.modules.nativeimage.api.debug.NIDebugger;
+import org.netbeans.modules.nativeimage.api.debug.NILineBreakpointDescriptor;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.filesystems.URLMapper;
+
+/**
+ * Gathers JPDA breakpoints and submits them to the native debugger.
+ */
+public class JPDABreakpointsHandler extends DebuggerManagerAdapter implements PropertyChangeListener {
+
+ private final File niFileSources;
+ private final NIDebugger debugger;
+ private final Set<JPDABreakpoint> attachedBreakpoints = new HashSet<>();
+
+ public JPDABreakpointsHandler(File niFile, NIDebugger debugger) {
+ this.niFileSources = getNativeSources(niFile);
+ this.debugger = debugger;
+ DebuggerManager dm = DebuggerManager.getDebuggerManager();
+ dm.addDebuggerListener(DebuggerManager.PROP_BREAKPOINTS, this);
+ Breakpoint[] bs = dm.getBreakpoints();
+ for (Breakpoint b : bs) {
+ add(b);
+ }
+ }
+
+ private static File getNativeSources(File niFile) {
+ File sources = new File(niFile.getParentFile(), "sources");
+ if (sources.isDirectory()) {
+ return sources;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void breakpointAdded(Breakpoint breakpoint) {
+ add(breakpoint);
+ }
+
+ @Override
+ public void breakpointRemoved(Breakpoint breakpoint) {
+ if (breakpoint instanceof JPDABreakpoint) {
+ breakpoint.removePropertyChangeListener(this);
+ debugger.removeBreakpoint(breakpoint);
+ synchronized (attachedBreakpoints) {
+ attachedBreakpoints.remove(breakpoint);
+ }
+ }
+ }
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ Object source = evt.getSource();
+ String propertyName = evt.getPropertyName();
+ if (source instanceof JPDABreakpoint && !(Breakpoint.PROP_DISPOSED.equals(propertyName) || Breakpoint.PROP_VALIDITY.equals(propertyName))) {
+ // Change of breakpoint properties
+ added((JPDABreakpoint) source);
+ }
+ }
+
+ private void add(Breakpoint b) {
+ if (b instanceof JPDABreakpoint && !((JPDABreakpoint) b).isHidden()) {
+ JPDABreakpoint jb = (JPDABreakpoint) b;
+ jb.addPropertyChangeListener(this);
+ synchronized (attachedBreakpoints) {
+ attachedBreakpoints.add(jb);
+ }
+ Breakpoint nativeBreakpoint = added(jb);
+ if (nativeBreakpoint != null) {
+ nativeBreakpoint.addPropertyChangeListener(Breakpoint.PROP_VALIDITY, e -> {
+ Breakpoint.VALIDITY validity = nativeBreakpoint.getValidity();
+ String validityMessage = nativeBreakpoint.getValidityMessage();
+ ((ChangeListener) jb).stateChanged(new ValidityChanger(validity, validityMessage));
+ });
+ }
+ }
+ }
+
+ private Breakpoint added(JPDABreakpoint b) {
+ if (b instanceof LineBreakpoint) {
+ LineBreakpoint lb = (LineBreakpoint) b;
+ URL url;
+ try {
+ url = new URL(lb.getURL());
+ } catch (MalformedURLException ex) {
+ return null;
+ }
+ String filePath = null;
+ if (niFileSources != null) {
+ FileObject fo;
+ fo = URLMapper.findFileObject(url);
+ for (FileObject root : GlobalPathRegistry.getDefault().getSourceRoots()) {
+ if (FileUtil.isParentOf(root, fo)) {
+ String path = FileUtil.getRelativePath(root, fo);
+ File sourcesFile = new File(niFileSources, path);
+ filePath = sourcesFile.getAbsolutePath();
+ break;
+ }
+ }
+ }
+ if (filePath == null) {
+ try {
+ filePath = new File(url.toURI()).getAbsolutePath();
+ } catch (URISyntaxException ex) {
+ return null;
+ }
+ }
+ NILineBreakpointDescriptor niBreakpointDescriptor = NILineBreakpointDescriptor.newBuilder(filePath, lb.getLineNumber())
+ .condition(lb.getCondition())
+ .enabled(lb.isEnabled())
+ .hidden(true)
+ .build();
+ Object nativeBreakpoint = debugger.addLineBreakpoint(lb, niBreakpointDescriptor);
+ return (Breakpoint) nativeBreakpoint;
+ }
+ return null;
+ }
+
+ public void dispose() {
+ synchronized (attachedBreakpoints) {
+ for (JPDABreakpoint jb : attachedBreakpoints) {
+ jb.removePropertyChangeListener(this);
+ debugger.removeBreakpoint(jb);
+ ((ChangeListener) jb).stateChanged(new ValidityChanger(Breakpoint.VALIDITY.UNKNOWN, null));
+ }
+ attachedBreakpoints.clear();
+ }
+ DebuggerManager.getDebuggerManager().removeDebuggerListener(DebuggerManager.PROP_BREAKPOINTS, this);
+ }
+
+ private static class ValidityChanger extends ChangeEvent {
+
+ private final String validityMessage;
+
+ ValidityChanger(Breakpoint.VALIDITY validity, String validityMessage) {
+ super(validity);
+ this.validityMessage = validityMessage;
+ }
+
+ @Override
+ public String toString() {
+ return validityMessage;
+ }
+ }
+}
diff --git a/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/displayer/JavaFrameDisplayer.java b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/displayer/JavaFrameDisplayer.java
new file mode 100644
index 0000000..2123c98
--- /dev/null
+++ b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/displayer/JavaFrameDisplayer.java
@@ -0,0 +1,206 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.nativeimage.debugger.displayer;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.classpath.GlobalPathRegistry;
+import org.netbeans.api.java.project.JavaProjectConstants;
+import org.netbeans.api.java.queries.SourceForBinaryQuery;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.api.project.SourceGroup;
+import org.netbeans.modules.nativeimage.api.debug.NIFrame;
+import org.netbeans.modules.nativeimage.spi.debug.filters.FrameDisplayer;
+import org.netbeans.spi.java.classpath.PathResourceImplementation;
+import org.netbeans.spi.java.classpath.support.ClassPathSupport;
+import org.openide.filesystems.FileObject;
+
+/**
+ * Display native frames like Java frames.
+ *
+ * @author martin
+ */
+public final class JavaFrameDisplayer implements FrameDisplayer {
+
+ private final ClassPath sourcePath;
+
+ public JavaFrameDisplayer(Project project) {
+ this.sourcePath = findSourcePath(project);
+ }
+
+ @Override
+ public DisplayedFrame displayed(NIFrame frame) {
+ String functionName = frame.getFunctionName();
+ if ("??".equals(functionName)) { // NOI18N
+ return null;
+ }
+ return createJavaFrame(frame);
+ }
+
+ private DisplayedFrame createJavaFrame(NIFrame frame) {
+ return DisplayedFrame.newBuilder(getDisplayName(frame))
+ .description(getDescription(frame))
+ .line(frame.getLine())
+ .sourceURISupplier(() -> getSourceURI(frame))
+ .build();
+ }
+
+ private static String getDisplayName(NIFrame frame) {
+ String functionName = frame.getFunctionName();
+ String clsMethod;
+ int methodEnd = functionName.indexOf('(');
+ if (methodEnd < 0) {
+ methodEnd = functionName.length();
+ }
+ int methodStart = functionName.lastIndexOf('.', methodEnd);
+ if (methodStart < 0) {
+ clsMethod = functionName.substring(0, methodEnd);
+ } else {
+ int clsStart = functionName.lastIndexOf('.', methodStart - 1);
+ if (clsStart < 0) {
+ clsStart = 0;
+ } else {
+ clsStart++;
+ }
+ clsMethod = functionName.substring(clsStart, methodEnd);
+ }
+ int line = frame.getLine();
+ if (line < 0) {
+ return clsMethod;
+ } else {
+ return clsMethod + ':' + line;
+ }
+ }
+
+ private static String getDescription(NIFrame frame) {
+ String functionName = frame.getFunctionName();
+ int methodEnd = functionName.indexOf('(');
+ if (methodEnd < 0) {
+ methodEnd = functionName.length();
+ }
+ String clsMethod = functionName.substring(0, methodEnd);
+ int line = frame.getLine();
+ if (line < 0) {
+ return clsMethod;
+ } else {
+ return clsMethod + ':' + line;
+ }
+ }
+
+ private URI getSourceURI(NIFrame frame) {
+ String functionName = frame.getFunctionName();
+ int methodEnd = functionName.indexOf('(');
+ if (methodEnd > 0) {
+ int methodStart = functionName.lastIndexOf('.', methodEnd);
+ if (methodStart > 0) {
+ String className = functionName.substring(0, methodStart);
+ URI uri = findClassURI(sourcePath, className);
+ if (uri != null) {
+ return uri;
+ }
+ }
+ }
+ String fullFileName = frame.getFullFileName();
+ if (fullFileName != null && !fullFileName.isEmpty()) {
+ return new File(fullFileName).toURI();
+ } else {
+ return null;
+ }
+ }
+
+ private static URI findClassURI(ClassPath sourcePath, String className) {
+ String sourceName = className;
+ int i = sourceName.indexOf ('$');
+ if (i > 0) {
+ sourceName = sourceName.substring (0, i);
+ }
+ sourceName = sourceName.replace('.', '/') + ".java";
+ FileObject resource;
+ if (sourcePath != null) {
+ resource = sourcePath.findResource(sourceName);
+ } else {
+ resource = GlobalPathRegistry.getDefault().findResource(sourceName);
+ }
+ if (resource != null) {
+ return resource.toURI();
+ } else {
+ return null;
+ }
+ }
+
+ private static ClassPath findSourcePath(Project project) {
+ if (project != null) {
+ List<FileObject> allSourceRoots = new ArrayList<>();
+ Set<FileObject> preferredRoots = new HashSet<>();
+ Set<FileObject> addedBinaryRoots = new HashSet<>();
+ SourceGroup[] sgs = ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
+ for (SourceGroup sg : sgs) {
+ ClassPath ecp = ClassPath.getClassPath(sg.getRootFolder(), ClassPath.EXECUTE);
+ if (ecp == null) {
+ ecp = ClassPath.getClassPath(sg.getRootFolder(), ClassPath.SOURCE);
+ }
+ if (ecp != null) {
+ FileObject[] binaryRoots = ecp.getRoots();
+ for (FileObject fo : binaryRoots) {
+ if (addedBinaryRoots.contains(fo)) {
+ continue;
+ }
+ addedBinaryRoots.add(fo);
+ FileObject[] roots = SourceForBinaryQuery.findSourceRoots(fo.toURL()).getRoots();
+ for (FileObject fr : roots) {
+ if (!preferredRoots.contains(fr)) {
+ allSourceRoots.add(fr);
+ preferredRoots.add(fr);
+ }
+ }
+ }
+ }
+ }
+ return createClassPath(allSourceRoots);
+ } else {
+ return null;
+ }
+ }
+
+ private static ClassPath createClassPath(Collection<FileObject> froots) {
+ List<PathResourceImplementation> pris = new ArrayList<> ();
+ for (FileObject fo : froots) {
+ if (fo != null && fo.canRead()) {
+ try {
+ URL url = fo.toURL();
+ pris.add(ClassPathSupport.createResource(url));
+ } catch (IllegalArgumentException iaex) {
+ // Can be thrown from ClassPathSupport.createResource()
+ // Ignore - bad source root
+ }
+ }
+ }
+ return ClassPathSupport.createClassPath(pris);
+ }
+
+}
diff --git a/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/displayer/JavaVariablesDisplayer.java b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/displayer/JavaVariablesDisplayer.java
new file mode 100644
index 0000000..191e2a9
--- /dev/null
+++ b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/displayer/JavaVariablesDisplayer.java
@@ -0,0 +1,596 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.nativeimage.debugger.displayer;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.netbeans.modules.nativeimage.api.debug.EvaluateException;
+import org.netbeans.modules.nativeimage.api.debug.NIDebugger;
+import org.netbeans.modules.nativeimage.api.debug.NIFrame;
+import org.netbeans.modules.nativeimage.api.debug.NIVariable;
+import org.netbeans.modules.nativeimage.spi.debug.filters.VariableDisplayer;
+
+/**
+ *
+ * @author martin
+ */
+public final class JavaVariablesDisplayer implements VariableDisplayer {
+
+ private static final String HUB = "__hub__";
+ private static final String ARRAY = "__array__";
+ private static final String ARRAY_LENGTH = "__length__";
+ private static final String COMPRESSED_REF_REFIX = "_z_.";
+ private static final String PUBLIC = "public";
+ private static final String STRING_VALUE = "value";
+ private static final String HASH = "hash";
+ private static final String UNSET = "<optimized out>";
+
+ private static final String[] STRING_TYPES = new String[] { String.class.getName(), StringBuilder.class.getName(), StringBuffer.class.getName() };
+
+ private NIDebugger debugger;
+
+ public JavaVariablesDisplayer() {
+ }
+
+ public void setDebugger(NIDebugger debugger) {
+ this.debugger = debugger;
+ }
+
+ @Override
+ public NIVariable[] displayed(NIVariable[] variables) {
+ List<NIVariable> displayedVars = new ArrayList<>(variables.length);
+ for (NIVariable var : variables) {
+ String value = var.getValue();
+ if (UNSET.equals(value)) {
+ continue;
+ }
+ int nch = var.getNumChildren();
+ NIVariable displayedVar;
+ if (nch == 0) {
+ String name = var.getName();
+ if (!name.equals(getNameOrIndex(name))) {
+ displayedVar = new Var(var);
+ } else {
+ displayedVar = var;
+ }
+ } else {
+ NIVariable[] children = var.getChildren();
+ NIVariable[] subChildren = children[0].getChildren();
+ // Check for Array
+ if (subChildren.length == 3 &&
+ //HUB.equals(subChildren[0].getName()) &&
+ ARRAY_LENGTH.equals(subChildren[1].getName()) &&
+ ARRAY.equals(subChildren[2].getName())) {
+ displayedVar = new ArrayVar(var, subChildren[1], subChildren[2]);
+ } else {
+ // Check for String
+ String type = getSimpleType(var.getType());
+ boolean isString = STRING_TYPES[0].equals(type);
+ boolean likeString = isString;
+ if (!likeString) {
+ for (String strType : STRING_TYPES) {
+ if (strType.equals(type)) {
+ likeString = true;
+ break;
+ }
+ }
+ }
+ if (likeString) {
+ displayedVar = new StringVar(var, type, isString ? null : subChildren);
+ } else {
+ if (children.length == 1 && PUBLIC.equals(children[0].getName())) {
+ // Object children
+ displayedVar = new ObjectVar(var, subChildren);
+ } else {
+ String name = var.getName();
+ if (!name.equals(getNameOrIndex(name))) {
+ displayedVar = new Var(var);
+ } else {
+ displayedVar = var;
+ }
+ }
+ }
+ }
+ }
+ displayedVars.add(displayedVar);
+ }
+ return displayedVars.toArray(new NIVariable[displayedVars.size()]);
+ }
+
+ private static String displayType(String type) {
+ if (type.startsWith(COMPRESSED_REF_REFIX)) {
+ type = type.substring(COMPRESSED_REF_REFIX.length());
+ }
+ if (type.endsWith("*")) {
+ type = type.substring(0, type.length() - 1).trim();
+ }
+ return type;
+ }
+
+ private static String getSimpleType(String type) {
+ type = displayType(type);
+ for (int i = 0; i < type.length(); i++) {
+ char c = type.charAt(i);
+ if (c != '.' && !Character.isJavaIdentifierPart(c)) {
+ return type.substring(0, i);
+ }
+ }
+ return type;
+ }
+
+ private static boolean isOfType(String varType, String type) {
+ varType = displayType(varType);
+ return varType.equals(type) || varType.startsWith(type) && !Character.isJavaIdentifierPart(varType.charAt(type.length()));
+ }
+
+ private static int getTypeSize(String type) {
+ type = getSimpleType(type);
+ switch (type) {
+ case "boolean":
+ case "byte":
+ return 1;
+ case "char":
+ case "short":
+ return 2;
+ case "int":
+ case "float":
+ return 4;
+ case "long":
+ case "double":
+ return 8;
+ default:
+ return 8;
+ }
+ }
+
+ private static Map<String, NIVariable> getVarsByName(NIVariable[] vars) {
+ switch (vars.length) {
+ case 0:
+ return Collections.emptyMap();
+ case 1:
+ return Collections.singletonMap(vars[0].getName(), vars[0]);
+ default:
+ Map<String, NIVariable> varsByName = new HashMap<>(vars.length);
+ for (NIVariable var : vars) {
+ varsByName.put(var.getName(), var);
+ }
+ return varsByName;
+ }
+ }
+
+ private static NIVariable[] restrictChildren(NIVariable[] children, int from, int to) {
+ if (from > 0 || to < children.length) {
+ to = Math.min(to, children.length);
+ if (from < to) {
+ children = Arrays.copyOfRange(children, from, to);
+ } else {
+ children = new NIVariable[]{};
+ }
+ }
+ return children;
+ }
+
+ private static String getHash(NIVariable[] children) {
+ for (NIVariable child : children) {
+ if (HASH.equals(child.getName())) {
+ String hash = child.getValue();
+ try {
+ hash = Integer.toHexString(Integer.parseInt(hash));
+ } catch (NumberFormatException ex) {}
+ return hash;
+ }
+ }
+ return null;
+ }
+
+ private static String getArrayExpression(NIVariable variable) {
+ StringBuilder arrayExpression = new StringBuilder(variable.getName());
+ while ((variable = variable.getParent()) != null) {
+ if (!PUBLIC.equals(variable.getName())) {
+ arrayExpression.insert(0, '.');
+ arrayExpression.insert(0, variable.getName());
+ }
+ }
+ return arrayExpression.toString();
+ }
+
+ private static String getNameOrIndex(String name) {
+ if (name.endsWith("]")) {
+ int i = name.lastIndexOf(ARRAY+"[");
+ if (i > 0) {
+ String index = name.substring(i + ARRAY.length() + 1, name.length() - 1);
+ return index;
+ }
+ }
+ return name;
+ }
+
+ private String readArray(NIVariable lengthVariable, int itemSize) {
+ int length = Integer.parseInt(lengthVariable.getValue());
+ String expressionPath = lengthVariable.getExpressionPath();
+ if (expressionPath != null && !expressionPath.isEmpty()) {
+ String addressExpr = "&" + expressionPath;
+ return debugger.readMemory(addressExpr, 4, length * itemSize); // length has 4 bytes
+ }
+ return null;
+ }
+
+ private static NIVariable[] getObjectChildren(NIVariable[] children, int from, int to) {
+ for (int i = 0; i < children.length; i++) {
+ if (HUB.equals(children[i].getName())) {
+ NIVariable[] ch1 = Arrays.copyOf(children, i);
+ NIVariable[] ch2 = Arrays.copyOfRange(children, i + 1, children.length);
+ if (ch1.length == 0) {
+ return ch2;
+ }
+ if (ch2.length == 0) {
+ return ch1;
+ }
+ NIVariable[] ch = new NIVariable[ch1.length + ch2.length];
+ System.arraycopy(ch1, 0, ch, 0, ch1.length);
+ System.arraycopy(ch2, 0, ch, ch1.length, ch2.length);
+ return ch;
+ }
+ }
+ return restrictChildren(children, from, to);
+ }
+
+ private class StringVar implements NIVariable {
+
+ private final NIVariable var;
+ private final String type;
+ private final NIVariable[] children;
+
+ StringVar(NIVariable var, String type, NIVariable[] children) {
+ this.var = var;
+ this.type = type;
+ this.children = children;
+ }
+
+ @Override
+ public NIFrame getFrame() {
+ return var.getFrame();
+ }
+
+ @Override
+ public String getName() {
+ return getNameOrIndex(var.getName());
+ }
+
+ @Override
+ public String getType() {
+ return type;
+ }
+
+ @Override
+ public String getValue() {
+ NIVariable pub = getVarsByName(var.getChildren()).get(PUBLIC);
+ Map<String, NIVariable> arrayInfo = getVarsByName(getVarsByName(pub.getChildren()).get(STRING_VALUE).getChildren());
+ arrayInfo = getVarsByName(arrayInfo.get(PUBLIC).getChildren());
+ NIVariable arrayVariable = arrayInfo.get(ARRAY);
+ NIVariable lengthVariable = arrayInfo.get(ARRAY_LENGTH);
+ String hexArray = readArray(lengthVariable, 2);
+ if (hexArray != null) {
+ return parseUTF16(hexArray);
+ } else { // legacy code
+ String arrayExpression = getArrayExpression(arrayVariable);
+ int length = Integer.parseInt(lengthVariable.getValue());
+ char[] characters = new char[length];
+ try {
+ for (int i = 0; i < length; i++) {
+ NIVariable charVar = debugger.evaluate(arrayExpression + "[" + i + "]", null, var.getFrame());
+ characters[i] = charVar.getValue().charAt(1);
+ }
+ } catch (EvaluateException ex) {
+ return ex.getLocalizedMessage();
+ }
+ return new String(characters);
+ }
+ }
+
+ private String parseUTF16(String hexArray) {
+ CharsetDecoder cd = Charset.forName("utf-16").newDecoder();
+ ByteBuffer buffer = ByteBuffer.allocate(2);
+ int length = hexArray.length() / 4;
+ char[] characters = new char[length];
+ int ih = 0;
+ for (int i = 0; i < length; i++) {
+ byte b1 = parseByte(hexArray, ih);
+ ih += 2;
+ byte b0 = parseByte(hexArray, ih);
+ ih += 2;
+ buffer.rewind();
+ buffer.put(b0);
+ buffer.put(b1);
+ buffer.rewind();
+ try {
+ char c = cd.decode(buffer).get();
+ characters[i] = c;
+ } catch (CharacterCodingException ex) {
+ }
+ }
+ return new String(characters);
+ }
+
+ private byte parseByte(String hexArray, int offset) {
+ String hex = new String(new char[] {hexArray.charAt(offset), hexArray.charAt(offset + 1)});
+ return (byte) (Integer.parseInt(hex, 16) & 0xFF);
+ }
+
+ @Override
+ public int getNumChildren() {
+ return children != null ? children.length : 0;
+ }
+
+ @Override
+ public NIVariable[] getChildren(int from, int to) {
+ return children != null ? getObjectChildren(children, from, to) : new NIVariable[]{};
+ }
+
+ @Override
+ public NIVariable getParent() {
+ return var.getParent();
+ }
+
+ @Override
+ public String getExpressionPath() {
+ return var.getExpressionPath();
+ }
+ }
+
+ private class ArrayVar implements NIVariable {
+
+ private final NIVariable var;
+ private final NIVariable lengthVariable;
+ private final int length;
+ private final NIVariable array;
+
+ ArrayVar(NIVariable var, NIVariable lengthVariable, NIVariable array) {
+ this.var = var;
+ this.lengthVariable = lengthVariable;
+ int arrayLength;
+ try {
+ arrayLength = Integer.parseInt(lengthVariable.getValue());
+ } catch (NumberFormatException ex) {
+ arrayLength = 0;
+ }
+ this.length = arrayLength;
+ this.array = array;
+ }
+
+ @Override
+ public NIFrame getFrame() {
+ return var.getFrame();
+ }
+
+ @Override
+ public NIVariable getParent() {
+ return var.getParent();
+ }
+
+ @Override
+ public String getName() {
+ return getNameOrIndex(var.getName());
+ }
+
+ @Override
+ public String getType() {
+ return displayType(var.getType());
+ }
+
+ @Override
+ public String getValue() {
+ String value = var.getValue();
+ if (value.startsWith("@")) {
+ value = getType() + value;
+ }
+ return value + "(length="+length+")";
+ }
+
+ @Override
+ public int getNumChildren() {
+ return length;
+ }
+
+ @Override
+ public NIVariable[] getChildren(int from, int to) {
+ if (from >= 0) {
+ to = Math.min(to, length);
+ } else {
+ from = 0;
+ to = length;
+ }
+ if (from >= to) {
+ return new NIVariable[]{};
+ }
+
+ String arrayAddress = null;
+ String expressionPath = lengthVariable.getExpressionPath();
+ if (expressionPath != null && !expressionPath.isEmpty()) {
+ String addressExpr = "&" + expressionPath;
+ NIVariable addressVariable;
+ try {
+ addressVariable = debugger.evaluate(addressExpr, null, lengthVariable.getFrame());
+ } catch (EvaluateException ex) {
+ addressVariable = null;
+ }
+ if (addressVariable != null) {
+ String address = addressVariable.getValue();
+ address = address.toLowerCase();
+ if (address.startsWith("0x")) {
+ arrayAddress = address;
+ }
+ }
+ }
+ NIVariable[] elements = new NIVariable[to - from];
+ try {
+ if (arrayAddress != null) {
+ String itemExpression = "*(" + getSimpleType(getType()) + "*)(" + arrayAddress + "+";
+ int size = getTypeSize(getType());
+ int offset = 4 + from*size;
+ for (int i = from; i < to; i++) {
+ NIVariable element = debugger.evaluate(itemExpression + offset + ")", Integer.toString(i), var.getFrame());
+ offset += size;
+ elements[i - from] = element;
+ }
+ } else {
+ String arrayExpression = getArrayExpression(array);
+ for (int i = from; i < to; i++) {
+ NIVariable element = debugger.evaluate(arrayExpression + "[" + i + "]", Integer.toString(i), var.getFrame());
+ elements[i - from] = element;
+ }
+ }
+ } catch (EvaluateException ex) {
+ return new NIVariable[]{};
+ }
+ return elements;
+ }
+
+ @Override
+ public String getExpressionPath() {
+ return var.getExpressionPath();
+ }
+ }
+
+ private class ObjectVar implements NIVariable {
+
+ private final NIVariable var;
+ private final NIVariable[] children;
+
+ ObjectVar(NIVariable var, NIVariable[] children) {
+ this.var = var;
+ this.children = children;
+ }
+
+ @Override
+ public NIFrame getFrame() {
+ return var.getFrame();
+ }
+
+ @Override
+ public NIVariable getParent() {
+ return var.getParent();
+ }
+
+ @Override
+ public String getName() {
+ return getNameOrIndex(var.getName());
+ }
+
+ @Override
+ public String getType() {
+ return displayType(var.getType());
+ }
+
+ @Override
+ public String getValue() {
+ String value = var.getValue();
+ if (value.startsWith("@") || value.startsWith("0x")) {
+ String hash = getHash(children);
+ if (hash == null) {
+ if (value.startsWith("@")) {
+ hash = value.substring(1);
+ } else {
+ hash = value.substring(2);
+ }
+ }
+ value = getType() + '@' + hash;
+ }
+ return value;
+ }
+
+ @Override
+ public int getNumChildren() {
+ return children.length;
+ }
+
+ @Override
+ public NIVariable[] getChildren(int from, int to) {
+ return getObjectChildren(children, from, to);
+ }
+
+ @Override
+ public String getExpressionPath() {
+ return var.getExpressionPath();
+ }
+ }
+
+ private class Var implements NIVariable {
+
+ private final NIVariable var;
+
+ Var(NIVariable var) {
+ this.var = var;
+ }
+
+ @Override
+ public NIFrame getFrame() {
+ return var.getFrame();
+ }
+
+ @Override
+ public NIVariable getParent() {
+ return var.getParent();
+ }
+
+ @Override
+ public String getName() {
+ return getNameOrIndex(var.getName());
+ }
+
+ @Override
+ public String getType() {
+ return var.getType();
+ }
+
+ @Override
+ public String getValue() {
+ return var.getValue();
+ }
+
+ @Override
+ public int getNumChildren() {
+ return var.getNumChildren();
+ }
+
+ @Override
+ public NIVariable[] getChildren(int from, int to) {
+ return var.getChildren(from, to);
+ }
+
+ @Override
+ public NIVariable[] getChildren() {
+ return var.getChildren();
+ }
+
+ @Override
+ public String getExpressionPath() {
+ return var.getExpressionPath();
+ }
+ }
+}
diff --git a/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/resources/mf-layer.xml b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/resources/mf-layer.xml
new file mode 100644
index 0000000..73421fc
--- /dev/null
+++ b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/resources/mf-layer.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.0//EN" "http://www.netbeans.org/dtds/filesystem-1_0.dtd">
+<filesystem>
+
+ <folder name="Editors">
+ <folder name="text">
+ </folder>
+ <folder name="AnnotationTypes">
+ </folder>
+ </folder>
+
+</filesystem>
diff --git a/java/java.nativeimage.debugger/test/unit/src/org/netbeans/modules/java/nativeimage/debugger/NIDebugRunnerTest.java b/java/java.nativeimage.debugger/test/unit/src/org/netbeans/modules/java/nativeimage/debugger/NIDebugRunnerTest.java
new file mode 100644
index 0000000..7ed9276
--- /dev/null
+++ b/java/java.nativeimage.debugger/test/unit/src/org/netbeans/modules/java/nativeimage/debugger/NIDebugRunnerTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.nativeimage.debugger;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collections;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.jpda.LineBreakpoint;
+import org.netbeans.modules.java.nativeimage.debugger.api.NIDebugRunner;
+import org.netbeans.modules.nativeimage.api.debug.EvaluateException;
+import org.netbeans.modules.nativeimage.api.debug.NIDebugger;
+import org.netbeans.modules.nativeimage.api.debug.NIVariable;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+import org.openide.util.lookup.ProxyLookup;
+
+/**
+ *
+ * @author martin
+ */
+public class NIDebugRunnerTest {
+
+ public NIDebugRunnerTest() {
+ }
+
+ private static Lookup getTestLookup() {
+ Lookup launchCtx = new ProxyLookup(
+ Lookups.fixed(new TestNIDebuggerServiceProvider()),
+ Lookup.getDefault()
+ );
+ return launchCtx;
+ }
+
+ @Test
+ public void testDebuggerProviderBreakpoints() {
+ LineBreakpoint bp1 = LineBreakpoint.create("file:///testFile", 10);
+ DebuggerManager.getDebuggerManager().addBreakpoint(bp1);
+ Lookups.executeWith(getTestLookup(), () -> {
+ NIDebugger debugger = NIDebugRunner.start(new File("NIFile"), Arrays.asList("ARG1", "ARG2"), "MI", null, "displayName", null, engine -> {});
+ try {
+ NIVariable result = debugger.evaluate("breakpoints", null, null);
+ assertEquals(1, result.getChildren().length);
+ assertEquals("/testFile:10", result.getChildren()[0].getValue());
+ } catch (EvaluateException ex) {
+ throw new AssertionError(ex.getLocalizedMessage(), ex);
+ }
+ });
+ DebuggerManager.getDebuggerManager().removeBreakpoint(bp1);
+ }
+
+ @Test
+ public void testVersion() {
+ Lookups.executeWith(getTestLookup(), () -> {
+ NIDebugger debugger = NIDebugRunner.start(new File("NIFile"), Collections.emptyList(), "MI", null, "displayName", null, engine -> {});
+ assertEquals("Test1", debugger.getVersion());
+ });
+ }
+}
diff --git a/java/java.nativeimage.debugger/test/unit/src/org/netbeans/modules/java/nativeimage/debugger/TestNIDebuggerProvider.java b/java/java.nativeimage.debugger/test/unit/src/org/netbeans/modules/java/nativeimage/debugger/TestNIDebuggerProvider.java
new file mode 100644
index 0000000..a514ddf
--- /dev/null
+++ b/java/java.nativeimage.debugger/test/unit/src/org/netbeans/modules/java/nativeimage/debugger/TestNIDebuggerProvider.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.nativeimage.debugger;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import org.netbeans.api.debugger.Breakpoint;
+import org.netbeans.api.debugger.DebuggerEngine;
+
+import org.netbeans.api.extexecution.ExecutionDescriptor;
+import org.netbeans.modules.nativeimage.api.debug.NIFrame;
+import org.netbeans.modules.nativeimage.api.debug.NILineBreakpointDescriptor;
+import org.netbeans.modules.nativeimage.api.debug.NIVariable;
+import org.netbeans.modules.nativeimage.spi.debug.NIDebuggerProvider;
+import org.netbeans.modules.nativeimage.spi.debug.filters.FrameDisplayer;
+import org.netbeans.modules.nativeimage.spi.debug.filters.VariableDisplayer;
+
+public class TestNIDebuggerProvider implements NIDebuggerProvider {
+
+ private final Map<Object, Breakpoint> breakpoints = new LinkedHashMap<>();
+ private FrameDisplayer frameDisplayer;
+ private VariableDisplayer variablesDisplayer;
+
+ public TestNIDebuggerProvider() {
+ }
+
+ @Override
+ public Breakpoint addLineBreakpoint(Object id, NILineBreakpointDescriptor breakpointDescriptor) {
+ Breakpoint nativeBreakpoint = new Breakpoint() {
+ @Override
+ public boolean isEnabled() {
+ return breakpointDescriptor.isEnabled();
+ }
+
+ @Override
+ public void disable() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void enable() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public String toString() {
+ return breakpointDescriptor.getFilePath() + ':' + breakpointDescriptor.getLine();
+ }
+ };
+ breakpoints.put(id, nativeBreakpoint);
+ return nativeBreakpoint;
+ }
+
+ @Override
+ public void removeBreakpoint(Object id) {
+ breakpoints.remove(id);
+ }
+
+ @Override
+ public void setFrameDisplayer(FrameDisplayer frameDisplayer) {
+ this.frameDisplayer = frameDisplayer;
+ }
+
+ @Override
+ public void setVariablesDisplayer(VariableDisplayer variablesDisplayer) {
+ this.variablesDisplayer = variablesDisplayer;
+ }
+
+ @Override
+ public CompletableFuture<Void> start(List<String> command, File workingDirectory, String debugger, String displayName, ExecutionDescriptor executionDescriptor, Consumer<DebuggerEngine> startedEngine) {
+ return CompletableFuture.completedFuture(null);
+ }
+
+ @Override
+ public CompletableFuture<NIVariable> evaluateAsync(String expression, String resultName, NIFrame frame) {
+ NIVariable result;
+ if ("breakpoints".equals(expression)) {
+ NIVariable[] children = new NIVariable[breakpoints.size()];
+ result = new TestNIVariable(expression, "BP", "BP", null, children, null);
+ int i = 0;
+ for (Breakpoint b : breakpoints.values()) {
+ children[i++] = new TestNIVariable("b" + i, "BP", b.toString(), result, new NIVariable[]{}, null);
+ }
+ } else {
+ result = new TestNIVariable(expression, "type", "value", null, new NIVariable[]{}, null);
+ }
+ result = variablesDisplayer.displayed(result)[0];
+ return CompletableFuture.completedFuture(result);
+ }
+
+ @Override
+ public String readMemory(String address, long offset, int length) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public String getVersion() {
+ return "Test1";
+ }
+
+}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java b/java/java.nativeimage.debugger/test/unit/src/org/netbeans/modules/java/nativeimage/debugger/TestNIDebuggerServiceProvider.java
similarity index 67%
rename from cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java
rename to java/java.nativeimage.debugger/test/unit/src/org/netbeans/modules/java/nativeimage/debugger/TestNIDebuggerServiceProvider.java
index 0fc9c76..7735bae 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/EvaluateException.java
+++ b/java/java.nativeimage.debugger/test/unit/src/org/netbeans/modules/java/nativeimage/debugger/TestNIDebuggerServiceProvider.java
@@ -16,17 +16,15 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.netbeans.modules.cpplite.debugger;
+package org.netbeans.modules.java.nativeimage.debugger;
-public final class EvaluateException extends Exception {
+import org.netbeans.modules.nativeimage.spi.debug.NIDebuggerProvider;
+import org.netbeans.modules.nativeimage.spi.debug.NIDebuggerServiceProvider;
- /**
- * Constructs an instance of <code>EvaluateException</code> with the
- * specified detail message.
- *
- * @param msg the detail message.
- */
- EvaluateException(String msg) {
- super(msg);
+public class TestNIDebuggerServiceProvider implements NIDebuggerServiceProvider {
+
+ @Override
+ public NIDebuggerProvider create() {
+ return new TestNIDebuggerProvider();
}
}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPVariable.java b/java/java.nativeimage.debugger/test/unit/src/org/netbeans/modules/java/nativeimage/debugger/TestNIVariable.java
similarity index 50%
copy from cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPVariable.java
copy to java/java.nativeimage.debugger/test/unit/src/org/netbeans/modules/java/nativeimage/debugger/TestNIVariable.java
index cd5c6fe..de5bde1 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPVariable.java
+++ b/java/java.nativeimage.debugger/test/unit/src/org/netbeans/modules/java/nativeimage/debugger/TestNIVariable.java
@@ -16,66 +16,67 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.netbeans.modules.cpplite.debugger;
+package org.netbeans.modules.java.nativeimage.debugger;
-import java.util.Map;
-import java.util.Objects;
+import org.netbeans.modules.nativeimage.api.debug.NIFrame;
+import org.netbeans.modules.nativeimage.api.debug.NIVariable;
-import org.netbeans.modules.cnd.debugger.gdb2.mi.MIConst;
-import org.netbeans.modules.cnd.debugger.gdb2.mi.MIValue;
+public class TestNIVariable implements NIVariable {
-/**
- * Representation of a variable.
- */
-public final class CPPVariable {
-
- private final CPPFrame frame;
- private final String uniqueName;
private final String name;
private final String type;
private final String value;
- private final int numChildren;
- private volatile Map<String, CPPVariable> children;
+ private final NIVariable parent;
+ private final NIVariable[] children;
+ private final NIFrame frame;
- CPPVariable(CPPFrame frame, String uniqueName, String name, String type, MIValue value, int numChildren) {
- this.frame = frame;
- this.uniqueName = uniqueName;
+ TestNIVariable(String name, String type, String value, NIVariable parent, NIVariable[] children, NIFrame frame) {
this.name = name;
this.type = type;
- this.value = (value instanceof MIConst) ? ((MIConst) value).value() : Objects.toString(value);
- this.numChildren = numChildren;
- }
-
- public String getUniqueName() {
- return uniqueName;
+ this.value = value;
+ this.parent = parent;
+ this.children = children;
+ this.frame = frame;
}
+ @Override
public String getName() {
return name;
}
+ @Override
public String getType() {
return type;
}
+ @Override
public String getValue() {
return value;
}
+ @Override
+ public NIVariable getParent() {
+ return parent;
+ }
+
+ @Override
public int getNumChildren() {
- return numChildren;
+ return children.length;
+ }
+
+ @Override
+ public NIVariable[] getChildren(int from, int to) {
+ return children;
}
- public Map<String, CPPVariable> getChildrenVariables() {
- Map<String, CPPVariable> vars = children;
- if (vars == null) {
- synchronized (this) {
- vars = children;
- if (vars == null) {
- children = vars = CPPFrame.retrieveVariables(frame, this);
- }
- }
- }
- return vars;
+ @Override
+ public NIFrame getFrame() {
+ return frame;
}
+
+ @Override
+ public String getExpressionPath() {
+ return "";
+ }
+
}
diff --git a/nbbuild/build.properties b/nbbuild/build.properties
index fc358a4..759f93a 100644
--- a/nbbuild/build.properties
+++ b/nbbuild/build.properties
@@ -211,6 +211,7 @@ config.javadoc.friend=\
java.j2seproject,\
junit,\
lib.v8debug,\
+ nativeimage.api,\
versioning.core,\
masterfs,\
masterfs.ui,\
diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties
index 4d447b1..7a93cd4 100644
--- a/nbbuild/cluster.properties
+++ b/nbbuild/cluster.properties
@@ -454,6 +454,7 @@ nb.cluster.ide=\
lsp.client,\
mercurial,\
mylyn.util,\
+ nativeimage.api,\
notifications,\
o.apache.commons.httpclient,\
o.apache.commons.lang,\
@@ -663,6 +664,7 @@ nb.cluster.java=\
java.metrics,\
java.module.graph,\
java.mx.project,\
+ java.nativeimage.debugger,\
java.navigation,\
java.openjdk.project,\
java.platform,\
diff --git a/nbbuild/javadoctools/links.xml b/nbbuild/javadoctools/links.xml
index 34a518f..5d07aaa 100644
--- a/nbbuild/javadoctools/links.xml
+++ b/nbbuild/javadoctools/links.xml
@@ -240,3 +240,4 @@
<link href="${javadoc.docs.org-netbeans-modules-java-editor-lib}" offline="true" packagelistloc="${netbeans.javadoc.dir}/org-netbeans-modules-java-editor-lib"/>
<link href="${javadoc.docs.org-netbeans-modules-web-common}" offline="true" packagelistloc="${netbeans.javadoc.dir}/org-netbeans-modules-web-common"/>
<link href="${javadoc.docs.org-netbeans-modules-db-core}" offline="true" packagelistloc="${netbeans.javadoc.dir}/org-netbeans-modules-db-core"/>
+<link href="${javadoc.docs.org-netbeans-modules-nativeimage-api}" offline="true" packagelistloc="${netbeans.javadoc.dir}/org-netbeans-modules-nativeimage-api"/>
diff --git a/nbbuild/javadoctools/properties.xml b/nbbuild/javadoctools/properties.xml
index 6f1abb8..3c633d1 100644
--- a/nbbuild/javadoctools/properties.xml
+++ b/nbbuild/javadoctools/properties.xml
@@ -237,3 +237,4 @@
<property name="javadoc.docs.org-netbeans-modules-java-editor-lib" value="${javadoc.web.root}/org-netbeans-modules-java-editor-lib"/>
<property name="javadoc.docs.org-netbeans-modules-web-common" value="${javadoc.web.root}/org-netbeans-modules-web-common"/>
<property name="javadoc.docs.org-netbeans-modules-db-core" value="${javadoc.web.root}/org-netbeans-modules-db-core"/>
+<property name="javadoc.docs.org-netbeans-modules-nativeimage-api" value="${javadoc.web.root}/org-netbeans-modules-nativeimage-api"/>
diff --git a/nbbuild/javadoctools/replaces.xml b/nbbuild/javadoctools/replaces.xml
index ce34768..f7e27e8 100644
--- a/nbbuild/javadoctools/replaces.xml
+++ b/nbbuild/javadoctools/replaces.xml
@@ -237,3 +237,4 @@
<replacefilter token="@org-netbeans-modules-java-editor-lib@" value="${javadoc.docs.org-netbeans-modules-java-editor-lib}"/>
<replacefilter token="@org-netbeans-modules-web-common@" value="${javadoc.docs.org-netbeans-modules-web-common}"/>
<replacefilter token="@org-netbeans-modules-db-core@" value="${javadoc.docs.org-netbeans-modules-db-core}"/>
+<replacefilter token="@org-netbeans-modules-nativeimage-api@" value="${javadoc.docs.org-netbeans-modules-nativeimage-api}"/>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists