CODENVY-257: GDB (#1016)

6.19.x
Anatoliy Bazko 2016-04-12 13:36:29 +03:00
parent 1bb4896c47
commit 66173e07f1
26 changed files with 377 additions and 150 deletions

View File

@ -31,8 +31,9 @@ import org.eclipse.che.generator.archetype.ArchetypeGenerator;
import org.eclipse.che.generator.archetype.ArchetypeGeneratorModule;
import org.eclipse.che.git.impl.nativegit.LocalGitUserResolver;
import org.eclipse.che.git.impl.nativegit.NativeGitConnectionFactory;
import org.eclipse.che.ide.ext.java.jdi.server.DebuggerService;
import org.eclipse.che.ide.ext.java.jdi.server.JavaDebuggerService;
import org.eclipse.che.ide.extension.maven.server.inject.MavenModule;
import org.eclipse.che.ide.gdb.server.GdbDebuggerService;
import org.eclipse.che.inject.DynaModule;
import org.eclipse.che.plugin.github.server.inject.GitHubModule;
import org.eclipse.che.security.oauth.RemoteOAuthTokenProvider;
@ -69,7 +70,8 @@ public class WsAgentModule extends AbstractModule {
install(new org.eclipse.che.swagger.deploy.DocsModule());
bind(ArchetypeGenerator.class);
bind(DebuggerService.class);
bind(JavaDebuggerService.class);
bind(GdbDebuggerService.class);
bind(GitUserResolver.class).to(LocalGitUserResolver.class);
bind(GitConnectionFactory.class).to(NativeGitConnectionFactory.class);

View File

@ -14,7 +14,6 @@
package org.eclipse.che.ide.ui.tree;
import org.eclipse.che.ide.util.browser.BrowserUtils;
import elemental.dom.Element;
import elemental.dom.NodeList;
import elemental.events.Event;
@ -23,15 +22,6 @@ import elemental.events.KeyboardEvent;
import elemental.events.MouseEvent;
import elemental.js.dom.JsElement;
import org.eclipse.che.ide.mvp.CompositeView;
import org.eclipse.che.ide.mvp.UiComponent;
import org.eclipse.che.ide.util.AnimationController;
import org.eclipse.che.ide.util.CssUtils;
import org.eclipse.che.ide.util.dom.DomUtils;
import org.eclipse.che.ide.util.dom.Elements;
import org.eclipse.che.ide.util.dom.MouseGestureListener;
import org.eclipse.che.ide.util.input.SignalEvent;
import org.eclipse.che.ide.util.input.SignalEventImpl;
import com.google.gwt.core.client.Duration;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.Scheduler;
@ -45,6 +35,16 @@ import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import org.eclipse.che.ide.mvp.CompositeView;
import org.eclipse.che.ide.mvp.UiComponent;
import org.eclipse.che.ide.util.AnimationController;
import org.eclipse.che.ide.util.CssUtils;
import org.eclipse.che.ide.util.browser.BrowserUtils;
import org.eclipse.che.ide.util.dom.DomUtils;
import org.eclipse.che.ide.util.dom.Elements;
import org.eclipse.che.ide.util.dom.MouseGestureListener;
import org.eclipse.che.ide.util.input.SignalEvent;
import org.eclipse.che.ide.util.input.SignalEventImpl;
import org.vectomatic.dom.svg.ui.SVGResource;
import java.util.ArrayList;

View File

@ -54,9 +54,6 @@ public interface DebuggerLocalizationConstant extends com.google.gwt.i18n.client
@Key("variables")
String variables();
@Key("absentInformationVariables")
String absentInformationVariables();
@Key("stepInto")
String stepInto();

View File

@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.che.ide.ext.debugger.client.debug;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.web.bindery.event.shared.EventBus;
@ -24,6 +25,7 @@ import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.api.promises.client.js.JsPromise;
import org.eclipse.che.api.promises.client.js.JsPromiseError;
import org.eclipse.che.api.promises.client.js.Promises;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.ide.api.filetypes.FileTypeRegistry;
import org.eclipse.che.ide.api.project.tree.VirtualFile;
import org.eclipse.che.ide.debug.Breakpoint;
@ -33,7 +35,6 @@ import org.eclipse.che.ide.debug.DebuggerManager;
import org.eclipse.che.ide.debug.DebuggerObservable;
import org.eclipse.che.ide.debug.DebuggerObserver;
import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.ext.debugger.client.fqn.FqnResolver;
import org.eclipse.che.ide.ext.debugger.client.fqn.FqnResolverFactory;
import org.eclipse.che.ide.ext.debugger.shared.BreakpointActivatedEvent;
import org.eclipse.che.ide.ext.debugger.shared.BreakpointEvent;
@ -76,13 +77,14 @@ public abstract class AbstractDebugger implements Debugger, DebuggerObservable {
public static final String LOCAL_STORAGE_DEBUGGER_KEY = "che-debugger";
protected final DtoFactory dtoFactory;
protected final DtoFactory dtoFactory;
protected final FileTypeRegistry fileTypeRegistry;
protected final FqnResolverFactory fqnResolverFactory;
private final List<DebuggerObserver> observers;
private final DebuggerServiceClient service;
private final LocalStorageProvider localStorageProvider;
private final EventBus eventBus;
private final FqnResolverFactory fqnResolverFactory;
private final ActiveFileHandler activeFileHandler;
private final DebuggerManager debuggerManager;
private final String id;
@ -94,7 +96,6 @@ public abstract class AbstractDebugger implements Debugger, DebuggerObservable {
private DebuggerInfo debuggerInfo;
private Location currentLocation;
private SubscriptionHandler<DebuggerEventList> debuggerEventsHandler;
private FileTypeRegistry fileTypeRegistry;
private MessageBus messageBus;
@ -216,7 +217,7 @@ public abstract class AbstractDebugger implements Debugger, DebuggerObservable {
final Location fLocation = location;
if (location != null) {
currentLocation = location;
activeFileHandler.openFile(resolveFilePathByLocation(location),
activeFileHandler.openFile(fqnToPath(location),
location.getClassName(),
location.getLineNumber(),
new AsyncCallback<VirtualFile>() {
@ -249,7 +250,7 @@ public abstract class AbstractDebugger implements Debugger, DebuggerObservable {
* <li>etc</li>
*/
private void onBreakpointActivated(Location location) {
List<String> filePaths = resolveFilePathByLocation(location);
List<String> filePaths = fqnToPath(location);
for (String filePath : filePaths) {
for (DebuggerObserver observer : observers) {
observer.onBreakpointActivated(filePath, location.getLineNumber() - 1);
@ -325,13 +326,11 @@ public abstract class AbstractDebugger implements Debugger, DebuggerObservable {
Location location = dtoFactory.createDto(Location.class);
location.setLineNumber(lineNumber + 1);
String mediaType = fileTypeRegistry.getFileTypeByFile(file).getMimeTypes().get(0);
final FqnResolver resolver = fqnResolverFactory.getResolver(mediaType);
if (resolver != null) {
location.setClassName(resolver.resolveFqn(file));
} else {
String fqn = pathToFqn(file);
if (fqn == null) {
return;
}
location.setClassName(fqn);
org.eclipse.che.ide.ext.debugger.shared.Breakpoint breakpoint =
dtoFactory.createDto(org.eclipse.che.ide.ext.debugger.shared.Breakpoint.class);
@ -367,13 +366,11 @@ public abstract class AbstractDebugger implements Debugger, DebuggerObservable {
Location location = dtoFactory.createDto(Location.class);
location.setLineNumber(lineNumber + 1);
String mediaType = fileTypeRegistry.getFileTypeByFile(file).getMimeTypes().get(0);
final FqnResolver resolver = fqnResolverFactory.getResolver(mediaType);
if (resolver != null) {
location.setClassName(resolver.resolveFqn(file));
} else {
Log.warn(AbstractDebugger.class, "FqnResolver is not found");
String fqn = pathToFqn(file);
if (fqn == null) {
return;
}
location.setClassName(fqn);
org.eclipse.che.ide.ext.debugger.shared.Breakpoint breakpoint =
dtoFactory.createDto(org.eclipse.che.ide.ext.debugger.shared.Breakpoint.class);
@ -430,14 +427,14 @@ public abstract class AbstractDebugger implements Debugger, DebuggerObservable {
Promise<Void> promise = connect.then(new Function<DebuggerInfo, Void>() {
@Override
public Void apply(DebuggerInfo arg) throws FunctionException {
public Void apply(final DebuggerInfo arg) throws FunctionException {
debuggerDescriptor.setInfo(arg.getName() + " " + arg.getVersion());
setDebuggerInfo(arg);
preserveDebuggerInfo();
startCheckingEvents();
startDebuggerWithDelay(arg);
service.start(arg.getId());
return null;
}
}).catchError(new Operation<PromiseError>() {
@ -455,6 +452,15 @@ public abstract class AbstractDebugger implements Debugger, DebuggerObservable {
return promise;
}
protected void startDebuggerWithDelay(final DebuggerInfo debuggerInfo) {
new Timer() {
@Override
public void run() {
service.start(debuggerInfo.getId());
}
}.schedule(2000);
}
@Override
public void disconnectDebugger() {
stopCheckingDebugEvents();
@ -480,7 +486,6 @@ public abstract class AbstractDebugger implements Debugger, DebuggerObservable {
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError arg) throws OperationException {
Log.error(AbstractDebugger.class, arg.getMessage());
for (DebuggerObserver observer : observers) {
observer.onDebuggerDisconnected();
}
@ -667,13 +672,15 @@ public abstract class AbstractDebugger implements Debugger, DebuggerObservable {
}
/**
* Create file path from {@link Location}.
*
* @param location
* location of class
* @return file path
* Transforms FQN to file path.
*/
abstract protected List<String> resolveFilePathByLocation(@NotNull Location location);
abstract protected List<String> fqnToPath(@NotNull Location location);
/**
* Transforms file path to FQN>
*/
@Nullable
abstract protected String pathToFqn(VirtualFile file);
abstract protected DebuggerDescriptor toDescriptor(Map<String, String> connectionProperties);
}

View File

@ -53,7 +53,7 @@ import static org.eclipse.che.ide.api.notification.StatusNotification.Status.PRO
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS;
/**
* The presenter provides debug java application.
* The presenter provides debugging applications.
*
* @author Vitaly Parfonov
* @author Artem Zatsarynnyi
@ -216,7 +216,7 @@ public class DebuggerPresenter extends BasePresenter implements DebuggerView.Act
variables.clear();
view.setVariables(variables);
view.setVMName("");
view.setExecutionPoint(true, null);
view.setExecutionPoint(null);
selectedVariable = null;
executionPoint = null;
}
@ -227,6 +227,9 @@ public class DebuggerPresenter extends BasePresenter implements DebuggerView.Act
} else {
view.setVMName(debuggerDescriptor.getInfo());
}
if (executionPoint != null) {
view.setExecutionPoint(executionPoint);
}
view.setBreakpoints(breakpointManager.getBreakpointList());
updateStackFrameDump();
@ -264,10 +267,6 @@ public class DebuggerPresenter extends BasePresenter implements DebuggerView.Act
List<DebuggerVariable> debuggerVariables = getDebuggerVariables(variables);
view.setVariables(debuggerVariables);
if (!debuggerVariables.isEmpty()) {
view.setExecutionPoint(variables.get(0).isExistInformation(), executionPoint);
}
DebuggerPresenter.this.variables = debuggerVariables;
}
}).catchError(new Operation<PromiseError>() {

View File

@ -45,12 +45,10 @@ public interface DebuggerView extends View<DebuggerView.ActionDelegate> {
/**
* Sets information about the execution point.
*
* @param absentInformation
* availability status for variables
* @param location
* information about the execution point
*/
void setExecutionPoint(boolean absentInformation, @NotNull Location location);
void setExecutionPoint(@NotNull Location location);
/**
* Sets variables.

View File

@ -209,17 +209,12 @@ public class DebuggerViewImpl extends BaseView<DebuggerView.ActionDelegate> impl
/** {@inheritDoc} */
@Override
public void setExecutionPoint(boolean existInformation, @Nullable Location location) {
public void setExecutionPoint(@Nullable Location location) {
StringBuilder labelText = new StringBuilder();
if (location != null) {
labelText.append("{").append(location.getClassName()).append(":").append(location.getLineNumber()).append("} ");
}
if (existInformation) {
executionPoint.getElement().setClassName(coreRes.coreCss().defaultFont());
} else {
labelText.append(locale.absentInformationVariables());
executionPoint.getElement().setClassName(coreRes.coreCss().warningFont());
}
executionPoint.getElement().setClassName(coreRes.coreCss().defaultFont());
executionPoint.setText(labelText.toString());
}

View File

@ -17,7 +17,6 @@ selectConfigurationActionEmptyCurrentConfigurationText=---
breakpoints = Breakpoints
debug = Debug
variables = Variables
absentInformationVariables = local variables debug info not available
host = Host:
port = Port:
debugActionTitle=Debug
@ -50,10 +49,12 @@ showHideDebuggerPanelDescription=Show/Hide Debugger Panel
debugger.connecting.title = Connecting to {0}
debugger.connected.title=Remote debugger connected
debugger.connected.description = Connected to the target VM, address: {0}.
debugger.connected.description = Connected to: {0}.
debugger.disconnected.title=Remote debugger disconnected
debugger.disconnected.description = Disconnected from the target VM, address: {0}
debugger.disconnected.description = Disconnected from: {0}
debugger.already.connected=Debugger already connected
failed.to.connect.to.remote.debugger.description=Can not connect to the target VM, address: {0}
failed.to.connect.to.remote.debugger.description=Can not connect to: {0}
failed.to.get.variable.value.title=Failed to get variable value
############### ChangeValueView ################

View File

@ -215,7 +215,7 @@ public class DebuggerPresenterTest extends BaseTest {
verify(view).setVariables(any());
verify(view).setVMName(eq(""));
verify(view).setExecutionPoint(eq(true), eq(null));
verify(view).setExecutionPoint(eq(null));
}
@Test
@ -224,7 +224,7 @@ public class DebuggerPresenterTest extends BaseTest {
verify(view).setVariables(any());
verify(view).setVMName(eq(""));
verify(view).setExecutionPoint(eq(true), eq(null));
verify(view).setExecutionPoint(eq(null));
}
@Test
@ -233,7 +233,7 @@ public class DebuggerPresenterTest extends BaseTest {
verify(view).setVariables(any());
verify(view).setVMName(eq(""));
verify(view).setExecutionPoint(eq(true), eq(null));
verify(view).setExecutionPoint(eq(null));
}
@Test
@ -242,7 +242,7 @@ public class DebuggerPresenterTest extends BaseTest {
verify(view).setVariables(any());
verify(view).setVMName(eq(""));
verify(view).setExecutionPoint(eq(true), eq(null));
verify(view).setExecutionPoint(eq(null));
}
@Test

View File

@ -11,6 +11,7 @@
package org.eclipse.che.ide.ext.debugger.client.debug;
import com.google.common.collect.ImmutableList;
import com.google.gwtmockito.GwtMockitoTestRunner;
import com.google.web.bindery.event.shared.EventBus;
import org.eclipse.che.api.machine.gwt.client.events.WsAgentStateEvent;
@ -46,6 +47,7 @@ import org.eclipse.che.ide.websocket.MessageBusProvider;
import org.eclipse.che.ide.websocket.rest.SubscriptionHandler;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
@ -76,6 +78,7 @@ import static org.mockito.Mockito.verify;
* @author Valeriy Svydenko
* @author Dmytro Nochevnov
*/
@RunWith(GwtMockitoTestRunner.class)
public class DebuggerTest extends BaseTest {
private static final String DEBUG_INFO = "debug_info";
private static final String DEBUGGER_ID = "debugger_id";
@ -227,15 +230,9 @@ public class DebuggerTest extends BaseTest {
public void testAttachDebuggerWithConnection() throws Exception {
Map<String, String> connectionProperties = mock(Map.class);
try {
debugger.attachDebugger(connectionProperties);
} catch (UnsatisfiedLinkError e) {
assertTrue(e.getMessage().contains("JsPromiseError.create")); // verify calling "Promises.resolve(null)"
verify(service, never()).connect(any());
return;
}
debugger.attachDebugger(connectionProperties);
fail("debugger.attachDebugger() didn't try to obtain rejected promise when there is a connection");
verify(service, never()).connect(any());
}
@Test
@ -256,7 +253,6 @@ public class DebuggerTest extends BaseTest {
operationVoidCaptor.getValue().apply(null);
operationPromiseErrorCaptor.getValue().apply(promiseError);
verify(promiseError).getMessage();
verify(observer, times(2)).onDebuggerDisconnected();
verify(debuggerManager, times(2)).setActiveDebugger(eq(null));
}
@ -265,15 +261,9 @@ public class DebuggerTest extends BaseTest {
public void testDisconnectDebuggerWithoutConnection() throws Exception {
debugger.setDebuggerInfo(null);
try {
debugger.disconnectDebugger();
} catch (UnsatisfiedLinkError e) {
assertTrue(e.getMessage().contains("Promises.resolve")); // verify calling "Promises.resolve(null)"
verify(service, never()).disconnect(any());
return;
}
debugger.disconnectDebugger();
fail("debugger.disconnectDebugger() didn't try to obtain disconnect promiseVoid from the method 'Promises.resolve(null)'");
verify(service, never()).disconnect(any());
}
@Test
@ -490,15 +480,9 @@ public class DebuggerTest extends BaseTest {
public void testGetValueWithoutConnection() throws Exception {
debugger.setDebuggerInfo(null);
try {
debugger.getValue(null);
} catch (UnsatisfiedLinkError e) {
assertTrue(e.getMessage().contains("JsPromiseError.create")); // verify calling "Promises.resolve(null)"
verify(service, never()).getValue(any(), any());
return;
}
debugger.getValue(null);
fail("debugger.getValue() didn't try to obtain rejected promise when there is no connection");
verify(service, never()).getValue(any(), any());
}
@Test
@ -532,15 +516,9 @@ public class DebuggerTest extends BaseTest {
public void testGetStackFrameDumpWithoutConnection() throws Exception {
debugger.setDebuggerInfo(null);
try {
debugger.getStackFrameDump();
} catch (UnsatisfiedLinkError e) {
assertTrue(e.getMessage().contains("JsPromiseError.create")); // verify calling "Promises.resolve(null)"
verify(service, never()).getStackFrameDump(any());
return;
}
debugger.getStackFrameDump();
fail("debugger.getStackFrameDump() didn't try to obtain rejected promise when there is no connection");
verify(service, never()).getStackFrameDump(any());
}
@Test
@ -556,16 +534,8 @@ public class DebuggerTest extends BaseTest {
@Test
public void testEvaluateExpressionWithoutConnection() throws Exception {
debugger.setDebuggerInfo(null);
try {
debugger.evaluateExpression("any");
} catch (UnsatisfiedLinkError e) {
assertTrue(e.getMessage().contains("JsPromiseError.create")); // verify calling "Promises.resolve(null)"
verify(service, never()).evaluateExpression(any(), any());
return;
}
fail("debugger.evaluateExpression() didn't try to obtain rejected promise when there is no connection");
debugger.evaluateExpression("any");
verify(service, never()).evaluateExpression(any(), any());
}
@Test
@ -606,10 +576,15 @@ public class DebuggerTest extends BaseTest {
}
@Override
protected List<String> resolveFilePathByLocation(@NotNull Location location) {
protected List<String> fqnToPath(@NotNull Location location) {
return Collections.emptyList();
}
@Override
protected String pathToFqn(VirtualFile file) {
return FQN;
}
@Override
protected DebuggerDescriptor toDescriptor(Map<String, String> connectionProperties) {
return debuggerDescriptor;

View File

@ -13,7 +13,10 @@ package org.eclipse.che.ide.gdb.client;
import com.google.inject.Inject;
import com.google.web.bindery.event.shared.EventBus;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.app.CurrentProject;
import org.eclipse.che.ide.api.filetypes.FileTypeRegistry;
import org.eclipse.che.ide.api.project.tree.VirtualFile;
import org.eclipse.che.ide.debug.DebuggerDescriptor;
import org.eclipse.che.ide.debug.DebuggerManager;
import org.eclipse.che.ide.dto.DtoFactory;
@ -41,6 +44,8 @@ public class GdbDebuggerClient extends AbstractDebugger {
public static final String ID = "gdb";
public static final String EVENTS_CHANNEL = "gdbdebugger:events:";
private final AppContext appContext;
@Inject
public GdbDebuggerClient(GdbDebuggerServiceClientImpl service,
DtoFactory dtoFactory,
@ -50,7 +55,8 @@ public class GdbDebuggerClient extends AbstractDebugger {
FqnResolverFactory fqnResolverFactory,
GdbDebuggerFileHandler activeFileHandler,
DebuggerManager debuggerManager,
FileTypeRegistry fileTypeRegistry) {
FileTypeRegistry fileTypeRegistry,
AppContext appContext) {
super(service,
dtoFactory,
@ -63,24 +69,37 @@ public class GdbDebuggerClient extends AbstractDebugger {
fileTypeRegistry,
ID,
EVENTS_CHANNEL);
this.appContext = appContext;
}
@Override
protected List<String> resolveFilePathByLocation(@NotNull Location location) {
Collections.singleton(location.getClassName());
return Collections.singletonList(location.getClassName());
protected List<String> fqnToPath(@NotNull Location location) {
CurrentProject currentProject = appContext.getCurrentProject();
if (currentProject == null) {
return Collections.singletonList(location.getClassName());
}
String projectPath = currentProject.getProjectConfig().getPath();
String path = projectPath + "/" + location.getClassName();
return Collections.singletonList(path);
}
@Override
protected String pathToFqn(VirtualFile file) {
return file.getName();
}
@Override
protected DebuggerDescriptor toDescriptor(Map<String, String> connectionProperties) {
String address = connectionProperties.get(connectionProperties.get(HOST.toString()) + ":" +
connectionProperties.get(PORT.toString()));
String address = connectionProperties.get(HOST.toString()) + ":" +
connectionProperties.get(PORT.toString());
return new DebuggerDescriptor("", address);
}
public enum ConnectionProperties {
HOST,
PORT,
FILE
BINARY,
SOURCES
}
}

View File

@ -33,9 +33,10 @@ import javax.validation.constraints.NotNull;
import java.util.Map;
import static org.eclipse.che.ide.MimeType.TEXT_PLAIN;
import static org.eclipse.che.ide.gdb.client.GdbDebuggerClient.ConnectionProperties.FILE;
import static org.eclipse.che.ide.gdb.client.GdbDebuggerClient.ConnectionProperties.BINARY;
import static org.eclipse.che.ide.gdb.client.GdbDebuggerClient.ConnectionProperties.HOST;
import static org.eclipse.che.ide.gdb.client.GdbDebuggerClient.ConnectionProperties.PORT;
import static org.eclipse.che.ide.gdb.client.GdbDebuggerClient.ConnectionProperties.SOURCES;
import static org.eclipse.che.ide.rest.HTTPHeader.ACCEPT;
import static org.eclipse.che.ide.rest.HTTPHeader.CONTENTTYPE;
@ -66,9 +67,14 @@ public class GdbDebuggerServiceClientImpl implements DebuggerServiceClient {
@Override
public Promise<DebuggerInfo> connect(@NotNull Map<String, String> connectionProperties) {
final String requestUrl = baseUrl + "/connect";
final String params = "?host=" + connectionProperties.get(HOST.toString())
String params = "?host=" + connectionProperties.get(HOST.toString())
+ "&port=" + connectionProperties.get(PORT.toString())
+ "&file=" + connectionProperties.get(FILE.toString());
+ "&file=" + connectionProperties.get(BINARY.toString());
String sources = connectionProperties.get(SOURCES.toString());
if (sources != null) {
params += "&sources=" + sources;
}
return asyncRequestFactory.createGetRequest(requestUrl + params)
.send(dtoUnmarshallerFactory.newUnmarshaller(DebuggerInfo.class));

View File

@ -28,7 +28,7 @@ import java.util.Map;
@Singleton
public class GdbConfigurationPagePresenter implements GdbConfigurationPageView.ActionDelegate, DebugConfigurationPage<DebugConfiguration> {
public static final String BIN_PATH_CONNECTION_PROPERTY = "binary-path";
public static final String BIN_PATH_CONNECTION_PROPERTY = "BINARY";
private final GdbConfigurationPageView view;

View File

@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.che.ide.gdb.server;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.ide.gdb.server.parser.GdbBreak;
import org.eclipse.che.ide.gdb.server.parser.GdbClear;
import org.eclipse.che.ide.gdb.server.parser.GdbContinue;
@ -20,12 +21,15 @@ import org.eclipse.che.ide.gdb.server.parser.GdbInfoArgs;
import org.eclipse.che.ide.gdb.server.parser.GdbInfoBreak;
import org.eclipse.che.ide.gdb.server.parser.GdbInfoLine;
import org.eclipse.che.ide.gdb.server.parser.GdbInfoLocals;
import org.eclipse.che.ide.gdb.server.parser.GdbInfoProgram;
import org.eclipse.che.ide.gdb.server.parser.GdbPType;
import org.eclipse.che.ide.gdb.server.parser.GdbParseException;
import org.eclipse.che.ide.gdb.server.parser.GdbPrint;
import org.eclipse.che.ide.gdb.server.parser.GdbRun;
import org.eclipse.che.ide.gdb.server.parser.GdbTargetRemote;
import org.eclipse.che.ide.gdb.server.parser.GdbVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.validation.constraints.NotNull;
import java.io.BufferedWriter;
@ -38,7 +42,7 @@ import java.io.OutputStreamWriter;
* @author Anatoliy Bazko
*/
public class Gdb extends GdbProcess {
private static final Logger LOG = LoggerFactory.getLogger(GdbProcess.class);
private static final String PROCESS_NAME = "gdb";
private static final String OUTPUT_SEPARATOR = "(gdb) ";
@ -122,9 +126,15 @@ public class Gdb extends GdbProcess {
/**
* `next` command.
*/
@Nullable
public GdbInfoLine next() throws IOException, InterruptedException, GdbParseException {
sendCommand("next");
outputs.take();
if (infoProgram().getStoppedAddress() == null) {
return null;
}
return infoLine();
}
@ -239,7 +249,17 @@ public class Gdb extends GdbProcess {
return GdbInfoLine.parse(outputs.take());
}
/**
* `info program` command.
*/
public GdbInfoProgram infoProgram() throws IOException, InterruptedException, GdbParseException {
sendCommand("info program");
return GdbInfoProgram.parse(outputs.take());
}
private void sendCommand(String command) throws IOException {
LOG.debug(command);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
writer.write(command);
writer.newLine();

View File

@ -22,9 +22,12 @@ import org.eclipse.che.ide.ext.debugger.shared.StackFrameDump;
import org.eclipse.che.ide.ext.debugger.shared.StepEvent;
import org.eclipse.che.ide.ext.debugger.shared.Value;
import org.eclipse.che.ide.ext.debugger.shared.Variable;
import org.eclipse.che.ide.ext.debugger.shared.VariablePath;
import org.eclipse.che.ide.gdb.server.parser.GdbContinue;
import org.eclipse.che.ide.gdb.server.parser.GdbDirectory;
import org.eclipse.che.ide.gdb.server.parser.GdbInfoBreak;
import org.eclipse.che.ide.gdb.server.parser.GdbInfoLine;
import org.eclipse.che.ide.gdb.server.parser.GdbInfoProgram;
import org.eclipse.che.ide.gdb.server.parser.GdbParseException;
import org.eclipse.che.ide.gdb.server.parser.GdbPrint;
import org.eclipse.che.ide.gdb.server.parser.GdbRun;
@ -111,7 +114,9 @@ public class GdbDebugger {
Gdb gdb;
try {
gdb = Gdb.start();
gdb.directory(srcDirectory);
GdbDirectory directory = gdb.directory(srcDirectory);
LOG.debug("Source directories: " + directory.getDirectories());
gdb.file(file);
if (port > 0) {
gdb.targetRemote(host, port);
@ -135,7 +140,7 @@ public class GdbDebugger {
public static GdbDebugger getInstance(String id) throws GdbDebuggerException {
GdbDebugger gdbDebugger = instances.get(id);
if (gdbDebugger == null) {
throw new GdbDebuggerException("Instance " + id + " not found");
throw new GdbDebuggerNotFoundException("Instance " + id + " not found");
}
return gdbDebugger;
@ -234,7 +239,7 @@ public class GdbDebugger {
try {
Breakpoint breakpoint;
if (getPort() > 0) {
if (isRemoteConnection()) {
GdbContinue gdbContinue = gdb.cont();
breakpoint = gdbContinue.getBreakpoint();
} else {
@ -250,18 +255,31 @@ public class GdbDebugger {
DebuggerEventList debuggerEventList = newDto(DebuggerEventList.class);
debuggerEventList.withEvents(Collections.singletonList(breakpointEvent));
publishWebSocketMessage(debuggerEventList, EVENTS_CHANNEL + id);
} else {
GdbInfoProgram gdbInfoProgram = gdb.infoProgram();
if (gdbInfoProgram.getStoppedAddress() == null) {
disconnect();
}
}
} catch (IOException | GdbParseException | InterruptedException e) {
throw new GdbDebuggerException("Error during running.", e);
}
}
private boolean isRemoteConnection() {
return getPort() > 0;
}
/**
* Does step over.
*/
public void stepOver() throws GdbDebuggerException {
try {
GdbInfoLine gdbInfoLine = gdb.next();
if (gdbInfoLine == null) {
disconnect();
return;
}
StepEvent stepEvent = newDto(StepEvent.class);
stepEvent.setType(DebuggerEvent.STEP);
@ -281,6 +299,10 @@ public class GdbDebugger {
public void stepInto() throws GdbDebuggerException {
try {
GdbInfoLine gdbInfoLine = gdb.step();
if (gdbInfoLine == null) {
disconnect();
return;
}
StepEvent stepEvent = newDto(StepEvent.class);
stepEvent.setType(DebuggerEvent.STEP);
@ -300,6 +322,10 @@ public class GdbDebugger {
public void stepOut() throws GdbDebuggerException {
try {
GdbInfoLine gdbInfoLine = gdb.finish();
if (gdbInfoLine == null) {
disconnect();
return;
}
StepEvent stepEvent = newDto(StepEvent.class);
stepEvent.setType(DebuggerEvent.STEP);
@ -329,6 +355,11 @@ public class GdbDebugger {
DebuggerEventList debuggerEventList = newDto(DebuggerEventList.class);
debuggerEventList.withEvents(Collections.singletonList(breakpointEvent));
publishWebSocketMessage(debuggerEventList, EVENTS_CHANNEL + id);
} else {
GdbInfoProgram gdbInfoProgram = gdb.infoProgram();
if (gdbInfoProgram.getStoppedAddress() == null) {
disconnect();
}
}
} catch (IOException | GdbParseException | InterruptedException e) {
throw new GdbDebuggerException("Resume error.", e);
@ -386,11 +417,20 @@ public class GdbDebugger {
List<Variable> variables = new ArrayList<>();
for (Map.Entry<String, String> e : locals.entrySet()) {
String varName = e.getKey();
String varValue = e.getValue();
String varType = gdb.ptype(varName).getType();
VariablePath variablePath = newDto(VariablePath.class);
variablePath.setPath(Collections.singletonList(varName));
Variable variable = newDto(Variable.class);
variable.setName(varName);
variable.setValue(e.getValue());
variable.setType(gdb.ptype(varName).getType());
variable.setValue(varValue);
variable.setType(varType);
variable.setVariablePath(variablePath);
variable.setExistInformation(true);
variable.setPrimitive(true);
variables.add(variable);
}

View File

@ -0,0 +1,21 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.gdb.server;
/**
* @author Anatoliy Bazko
*/
@SuppressWarnings("serial")
public class GdbDebuggerNotFoundException extends GdbDebuggerException {
public GdbDebuggerNotFoundException(String message) {
super(message);
}
}

View File

@ -17,6 +17,7 @@ import org.eclipse.che.ide.ext.debugger.shared.DebuggerInfo;
import org.eclipse.che.ide.ext.debugger.shared.StackFrameDump;
import org.eclipse.che.ide.ext.debugger.shared.UpdateVariableRequest;
import org.eclipse.che.ide.ext.debugger.shared.Value;
import org.eclipse.che.ide.ext.debugger.shared.Variable;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
@ -57,12 +58,12 @@ public class GdbDebuggerService {
public DebuggerInfo create(@QueryParam("host") String host,
@QueryParam("port") @DefaultValue("0") int port,
@QueryParam("file") String file,
@QueryParam("sources") String srcDirectory) throws GdbDebuggerException {
if (srcDirectory == null) {
srcDirectory = Paths.get(file).getParent().toString();
@QueryParam("sources") String sources) throws GdbDebuggerException {
if (sources == null) {
sources = Paths.get(file).getParent().toString();
}
GdbDebugger d = GdbDebugger.newInstance(host, port, file, srcDirectory);
GdbDebugger d = GdbDebugger.newInstance(host, port, file, sources);
return DtoFactory.getInstance().createDto(DebuggerInfo.class)
.withHost(d.getHost())
.withPort(d.getPort())
@ -81,7 +82,11 @@ public class GdbDebuggerService {
@GET
@Path("disconnect/{id}")
public void disconnect(@PathParam("id") String id) throws GdbDebuggerException {
GdbDebugger.getInstance(id).disconnect();
try {
GdbDebugger.getInstance(id).disconnect();
} catch (GdbDebuggerNotFoundException e) {
// ignore
}
}
@GET
@ -128,8 +133,8 @@ public class GdbDebuggerService {
@Path("value/get/{id}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Value getValue(@PathParam("id") String id, String variable) throws GdbDebuggerException {
return GdbDebugger.getInstance(id).getValue(variable);
public Value getValue(@PathParam("id") String id, Variable variable) throws GdbDebuggerException {
return GdbDebugger.getInstance(id).getValue(variable.getName());
}
@POST

View File

@ -109,6 +109,8 @@ public abstract class GdbProcess {
GdbOutput gdbOutput = GdbOutput.of(buf.substring(0, indexOf));
outputs.add(gdbOutput);
LOG.debug(gdbOutput.getOutput());
buf.delete(0, indexOf + outputSeparator.length());
}
}

View File

@ -23,7 +23,7 @@ import java.util.regex.Pattern;
*/
public class GdbInfoLine {
private static final Pattern GDB_INFO_LINE = Pattern.compile("Line ([0-9]*) of \"(.*)\" starts at .*");
private static final Pattern GDB_INFO_LINE = Pattern.compile("Line ([0-9]*) of \"(.*)\"\\s*starts at .*");
private final Location location;
@ -53,6 +53,6 @@ public class GdbInfoLine {
return new GdbInfoLine(location);
}
throw new GdbParseException(GdbTargetRemote.class, output);
throw new GdbParseException(GdbInfoLine.class, output);
}
}

View File

@ -0,0 +1,56 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.gdb.server.parser;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 'info program' command parser.
*
* @author Anatoliy Bazko
*/
public class GdbInfoProgram {
private static final Pattern GDB_PROGRAM_STOPPED = Pattern.compile(".*Program stopped at (.*)[.]\n.*");
private static final Pattern GDB_PROGRAM_FINISHED = Pattern.compile(".*The program being debugged is not being run.*");
private final String address;
public GdbInfoProgram(String address) {
this.address = address;
}
public String getStoppedAddress() {
return address;
}
/**
* Factory method.
*/
public static GdbInfoProgram parse(GdbOutput gdbOutput) throws GdbParseException {
String output = gdbOutput.getOutput();
Matcher matcher = GDB_PROGRAM_FINISHED.matcher(output);
if (matcher.find()) {
return new GdbInfoProgram(null);
}
matcher = GDB_PROGRAM_STOPPED.matcher(output);
if (matcher.find()) {
String address = matcher.group(1);
return new GdbInfoProgram(address);
}
throw new GdbParseException(GdbInfoProgram.class, output);
}
}

View File

@ -72,7 +72,7 @@ public class GdbDebuggerTest {
addBreakpoint();
startDebugger();
doSetAndGetValues();
stepInto();
// stepInto();
stepOver();
stepOut();
resume();
@ -147,8 +147,7 @@ public class GdbDebuggerTest {
assertTrue(debuggerEvent instanceof StepEvent);
StepEvent stepEvent = (StepEvent)debuggerEvent;
assertEquals(stepEvent.getLocation().getClassName(), "h.cpp");
assertEquals(stepEvent.getLocation().getLineNumber(), 5);
assertNotNull(stepEvent.getLocation());
gdbDebugger.stepInto();
@ -156,8 +155,7 @@ public class GdbDebuggerTest {
assertTrue(debuggerEvent instanceof StepEvent);
stepEvent = (StepEvent)debuggerEvent;
assertEquals(stepEvent.getLocation().getClassName(), "h.cpp");
assertEquals(stepEvent.getLocation().getLineNumber(), 6);
assertNotNull(stepEvent.getLocation());
gdbDebugger.stepInto();
@ -165,8 +163,7 @@ public class GdbDebuggerTest {
assertTrue(debuggerEvent instanceof StepEvent);
stepEvent = (StepEvent)debuggerEvent;
assertEquals(stepEvent.getLocation().getClassName(), "h.cpp");
assertEquals(stepEvent.getLocation().getLineNumber(), 7);
assertNotNull(stepEvent.getLocation());
}
private void doSetAndGetValues() throws GdbDebuggerException {

View File

@ -14,6 +14,7 @@ import org.eclipse.che.ide.ext.debugger.shared.Breakpoint;
import org.eclipse.che.ide.gdb.server.parser.GdbContinue;
import org.eclipse.che.ide.gdb.server.parser.GdbInfoBreak;
import org.eclipse.che.ide.gdb.server.parser.GdbInfoLine;
import org.eclipse.che.ide.gdb.server.parser.GdbInfoProgram;
import org.eclipse.che.ide.gdb.server.parser.GdbPType;
import org.eclipse.che.ide.gdb.server.parser.GdbParseException;
import org.eclipse.che.ide.gdb.server.parser.GdbPrint;
@ -29,6 +30,7 @@ import java.util.List;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
/**
@ -157,16 +159,10 @@ public class GdbTest {
gdb.run();
GdbInfoLine gdbInfoLine = gdb.step();
assertNotNull(gdbInfoLine.getLocation());
assertEquals(gdbInfoLine.getLocation().getLineNumber(), 5);
assertEquals(gdbInfoLine.getLocation().getClassName(), "h.cpp");
gdbInfoLine = gdb.step();
assertNotNull(gdbInfoLine.getLocation());
assertEquals(gdbInfoLine.getLocation().getLineNumber(), 6);
assertEquals(gdbInfoLine.getLocation().getClassName(), "h.cpp");
}
@Test
@ -205,4 +201,24 @@ public class GdbTest {
GdbPType gdbPType = gdb.ptype("i");
assertEquals(gdbPType.getType(), "int");
}
@Test
public void testInfoProgram() throws Exception {
gdb.file(file);
GdbInfoProgram gdbInfoProgram = gdb.infoProgram();
assertNull(gdbInfoProgram.getStoppedAddress());
gdb.breakpoint(4);
gdb.run();
gdbInfoProgram = gdb.infoProgram();
assertNotNull(gdbInfoProgram.getStoppedAddress());
GdbContinue gdbContinue = gdb.cont();
assertNull(gdbContinue.getBreakpoint());
gdbInfoProgram = gdb.infoProgram();
assertNull(gdbInfoProgram.getStoppedAddress());
}
}

View File

@ -21,7 +21,7 @@ import static org.testng.Assert.assertEquals;
public class GdbInfoLineTest {
@Test
public void testParse() throws Exception {
public void testParse1() throws Exception {
GdbOutput gdbOutput = GdbOutput.of("Line 6 of \"h.cpp\" starts at address 0x4008ae <main()+17> and ends at 0x4008ca <main()+45>.\n");
GdbInfoLine gdbInfoLine = GdbInfoLine.parse(gdbOutput);
@ -30,4 +30,17 @@ public class GdbInfoLineTest {
assertEquals(location.getClassName(), "h.cpp");
assertEquals(location.getLineNumber(), 6);
}
}
@Test
public void testParse2() throws Exception {
GdbOutput gdbOutput = GdbOutput.of("Line 530 of \"/usr/src/debug/gcc-4.8.3-20140911/obj-x86_64-redhat-linux/x86_64-redhat-linux/libstdc++-v3/include/ostream\"\n" +
" starts at address 0x3e8ba94e60 <std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)>\n" +
" and ends at 0x3e8ba94e6c <std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)+12>.\n");
GdbInfoLine gdbInfoLine = GdbInfoLine.parse(gdbOutput);
Location location = gdbInfoLine.getLocation();
assertEquals(location.getClassName(), "/usr/src/debug/gcc-4.8.3-20140911/obj-x86_64-redhat-linux/x86_64-redhat-linux/libstdc++-v3/include/ostream");
assertEquals(location.getLineNumber(), 530);
}
}

View File

@ -0,0 +1,41 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.gdb.server.parser;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
/**
* @author Anatoliy Bazko
*/
public class GdbInfoProgramTest {
@Test
public void testProgramIsFinished() throws Exception {
GdbOutput gdbOutput = GdbOutput.of("The program being debugged is not being run.\n");
GdbInfoProgram gdbInfoProgram = GdbInfoProgram.parse(gdbOutput);
assertNull(gdbInfoProgram.getStoppedAddress());
}
@Test
public void testProgramIsStopped() throws Exception {
GdbOutput gdbOutput = GdbOutput.of("Debugging a target over a serial line.\n" +
"Program stopped at 0x7ffff7ddb2d0.\n" +
"It stopped with signal SIGTRAP, Trace/breakpoint trap.\n");
GdbInfoProgram gdbInfoProgram = GdbInfoProgram.parse(gdbOutput);
assertEquals(gdbInfoProgram.getStoppedAddress(), "0x7ffff7ddb2d0");
}
}

View File

@ -16,10 +16,12 @@ import com.google.web.bindery.event.shared.EventBus;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.app.CurrentProject;
import org.eclipse.che.ide.api.filetypes.FileTypeRegistry;
import org.eclipse.che.ide.api.project.tree.VirtualFile;
import org.eclipse.che.ide.debug.DebuggerDescriptor;
import org.eclipse.che.ide.debug.DebuggerManager;
import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.ext.debugger.client.debug.AbstractDebugger;
import org.eclipse.che.ide.ext.debugger.client.fqn.FqnResolver;
import org.eclipse.che.ide.ext.debugger.client.fqn.FqnResolverFactory;
import org.eclipse.che.ide.ext.debugger.shared.Location;
import org.eclipse.che.ide.ext.java.client.projecttree.JavaSourceFolderUtil;
@ -65,7 +67,7 @@ public class JavaDebugger extends AbstractDebugger {
}
@Override
protected List<String> resolveFilePathByLocation(@NotNull Location location) {
protected List<String> fqnToPath(@NotNull Location location) {
CurrentProject currentProject = appContext.getCurrentProject();
if (currentProject == null) {
@ -85,6 +87,21 @@ public class JavaDebugger extends AbstractDebugger {
return filePaths;
}
@Override
protected String pathToFqn(VirtualFile file) {
List<String> mimeTypes = fileTypeRegistry.getFileTypeByFile(file).getMimeTypes();
if (!mimeTypes.isEmpty()) {
String mediaType = mimeTypes.get(0);
FqnResolver resolver = fqnResolverFactory.getResolver(mediaType);
if (resolver != null) {
return resolver.resolveFqn(file);
}
}
return null;
}
@Override
protected DebuggerDescriptor toDescriptor(Map<String, String> connectionProperties) {
String address = connectionProperties.get(HOST.toString()) + ":" + connectionProperties.get(PORT.toString());

View File

@ -34,7 +34,7 @@ import javax.ws.rs.core.MediaType;
* @author andrew00x
*/
@Path("debug-java/{ws-id}")
public class DebuggerService {
public class JavaDebuggerService {
@GET
@Path("{id}")